2 votes

Récupérer le résultat d'une requête parent/enfant SQL Server avec c#

Ce que je fais maintenant est probablement la pire façon de répondre à mes exigences, mais je n'ai pas trouvé d'autre moyen.

Voici mon exemple de structure de base de données ;

enter image description here

Voici le script que j'utilise pour récupérer certaines valeurs ;

SELECT DISTINCT h.HotelID, h.HotelName, r.RoomCode, r.RoomName, r.RoomID 
FROM RoomsInHotel rh 
INNER JOIN Hotels h ON rh.HotelID = h.HotelID 
INNER JOIN  Rooms r ON rh.RoomID = r.RoomID 
order by h.HotelName, r.RoomCode;

Voici le résultat que le script ci-dessus me renvoie ;

enter image description here

Tout va bien jusqu'ici.

Je dois passer au code C# à partir d'ici. Ce que j'aimerais obtenir est le résultat suivant ;

enter image description here

Voici ce qui me préoccupe. J'utilise Linq pour réaliser cette chose et le code ci-dessous est le code que j'ai utilisé pour le résultat de la console ci-dessus.

    public class Hotel { 
      public int HotelID {get; set; }
      public string HotelName {get; set; }
      public IQueryable<Room> Rooms {get; set; }
    }

    public class HotelWithOneRoom {
        public int HotelID { get; set; }
        public string HotelName { get; set; }
        public Room Room { get; set; }
    }

    public class Room { 
      public int RoomID {get; set; }
      public string RoomCode {get; set; }
      public string RoomName { get; set; }
    }

    class Program {

        static void Main(string[] args) {

            #region _assets

            IList<HotelWithOneRoom> tempHotelWithOneRoom = new List<HotelWithOneRoom>();
            IList<Hotel> tempDistinctHotels = new List<Hotel>();
            IList<Room> tempRooms = new List<Room>();

            #endregion

            #region _connectionString

            var connectionString = "Data Source=TOSHIBA-PC\\SQLEXPRESS;Initial Catalog=tbAccomm;Integrated Security=True";

            #endregion

            using (SqlConnection conn = new SqlConnection(connectionString)) {

                using(SqlCommand cmd = conn.CreateCommand()) {

                    #region _connect to db, generate script and retrieve values

                    cmd.CommandText = "SELECT DISTINCT h.HotelID, h.HotelName, r.RoomCode, r.RoomName, r.RoomID FROM RoomsInHotel rh INNER JOIN Hotels h ON rh.HotelID = h.HotelID INNER JOIN Rooms r ON rh.RoomID = r.RoomID order by h.HotelName, r.RoomCode;";
                    cmd.CommandType = System.Data.CommandType.Text;

                    conn.Open();
                    SqlDataReader r = cmd.ExecuteReader();

                    #endregion

                    #region _assigning the values to tempHotelWithOneRoom

                    while (r.Read()) {

                        tempHotelWithOneRoom.Add(new HotelWithOneRoom {
                            HotelID = int.Parse(r["HotelID"].ToString()),
                            HotelName = r["HotelName"].ToString(),
                            Room = new Room {
                                RoomID = int.Parse(r["RoomID"].ToString()),
                                RoomCode = r["RoomCode"].ToString(),
                                RoomName = r["RoomName"].ToString()
                            }
                        });
                    }

                    #endregion

                    foreach (var item in tempHotelWithOneRoom) {

                        if (tempDistinctHotels.Where(x => x.HotelID == item.HotelID).Count() < 1) {

                            tempDistinctHotels.Add(new Hotel { 
                                HotelID = item.HotelID,
                                HotelName = item.HotelName
                            });

                            var _tempHotel = tempDistinctHotels.Single(x => x.HotelID == item.HotelID);
                            var _tempRoomList = new List<Room>();

                            if (_tempHotel.Rooms != null) { 
                                foreach (var _item in _tempHotel.Rooms) {
                                    _tempRoomList.Add(_item);
                                }
                            }

                            _tempRoomList.Add( new Room { 
                                RoomCode = item.Room.RoomCode,
                                RoomID = item.Room.RoomID,
                                RoomName = item.Room.RoomName
                            });

                            _tempHotel.Rooms = _tempRoomList.AsQueryable();

                        } else {

                            var _tempHotel = tempDistinctHotels.Single(x => x.HotelID == item.HotelID);
                            var _tempRoomList = new List<Room>();

                            if (_tempHotel.Rooms != null) { 
                                foreach (var _item in _tempHotel.Rooms) {
                                    _tempRoomList.Add(_item);
                                }
                            }

                            _tempRoomList.Add( new Room { 
                                RoomCode = item.Room.RoomCode,
                                RoomID = item.Room.RoomID,
                                RoomName = item.Room.RoomName
                            });

                            _tempHotel.Rooms = _tempRoomList.AsQueryable();
                        }
                    }

                    #region _output the result

                    foreach (var item in tempDistinctHotels) {

                        Console.WriteLine(
                            "Hotel Name : " + item.HotelName + ", " +  "Room Count : " + item.Rooms.Count()
                            );

                        foreach (var item2 in item.Rooms) {
                            Console.WriteLine("--" + item2.RoomCode + ", " + item2.RoomName);
                        }
                    }

                    #endregion

                    r.Close();
                    Console.Read();
                }

            }

        }
    }

IMO, s'il y avait une compétition sur le pire code c#, je gagnerais cette compétition avec ce code. (Le ferais-je ?)

Quelle est donc la manière la plus optimisée de faire ce que je fais ?

3voto

Stephan B Points 2671

C# n'est pas mon langage de prédilection, mais voilà :

Dictionary<int, Hotel> Hotels = new Dictionary<int, Hotel> ();
while (r.Read()) {
    if (!Hotels.ContainsKey(r["HotelID"])) {
        NewHotel Hotel= new Hotel();
        NewHotel.HotelID = r["HotelID"];
        Newhotel.HotelName = r["HotelName"];
        NewHotel.Rooms = new Dictionary<int, Room> ();
        Hotels.Add(NewHotel);
    }
    Room NewRoom = new Room();
    NewRoom.RoomID = r["RoomName"];
    NewRoom.RoomCode = r["RoomCode"];
    NewRoom.RoomName = r["RoomName"];
    Hotels.Items("HotelID").Rooms.Add(NewRoom);
}

Comme l'a souligné jpmcclung, vous aurez besoin de compétences en génie logiciel pour créer des applications réussies. Plus votre projet est important, plus la conception et la planification sont nécessaires.

1voto

jpmcclung Points 84

La meilleure façon d'éviter d'écrire un tel code est d'étudier la pratique de la conception pilotée par les tests. Ce code le réclame à cor et à cri. Pour le voir en action, je vous conseille de regarder la nouvelle vidéo TDD Full Throttle de Brad Wilson sur TekPub (http://shop.tekpub.com/products/ft\_tdd\_wilson). Elle coûte 12 dollars, mais elle en vaut la peine. Sinon, il existe de nombreuses ressources sur le sujet.

Plus précisément, pourquoi avez-vous besoin d'un HotelWithOneRoom ? Il suffit d'ajouter une chambre à la liste des chambres d'un hôtel ordinaire. Pourquoi ne pas surcharger .ToString() sur Hotel et utiliser StringBuilder pour créer la ligne de sortie pour un hôtel ? Ce ne sont là que quelques exemples qui me viennent à l'esprit, mais si vous utilisez le TDD, cela vous aidera à organiser vos pratiques de conception et à vous débarrasser d'une partie de ce code.

1voto

Jim Wooley Points 6323

Puisque vous incluez IQueryable dans votre exemple, pouvons-nous supposer que LINQ to SQL ou EF est une option pour votre solution ? Si c'est le cas, sachez qu'ils permettent de projeter directement dans les hiérarchies d'objets.

En supposant que vous disposiez d'associations entre vos tables, cela pourrait être aussi simple que cela :

var query = from hotel in context.hotels
             select new Hotel { HotelID = hotel.HotelID,
                                HotelName = hotel.HotelName,
                                Rooms = (from room in hotel.Rooms
                                        select new Room { 
                                            RoomID = room.RoomID,
                                            RoomCode = room.RoomCode, 
                                            RoomName = room.RoomName })
                                        .Distinct()
             };

0voto

Jeff Reddy Points 2110

Je pense que vous pourriez commencer par le début et éviter toute confusion en renommant vos tableaux. Je pense que les noms de vos tables devraient être Hôtel, Chambre et Type de chambre (je ne suis pas un fan des noms de tables au pluriel, mais ce n'est pas le sujet).

En termes de "domaine", vous disposez d'un hôtel. Un hôtel a des chambres. Chaque chambre est définie comme un type de chambre, double, simple, etc...

Quoi qu'il en soit, j'ai créé un code qui fait la même chose que le vôtre. C'est un peu plus clair, je pense. Pour l'accès à la base de données, j'ai utilisé Massive https://github.com/robconery/massive parce que c'est rapide et amusant.

Quoi qu'il en soit, voici le code que j'ai trouvé.

    class Program {
        static void Main(string[] args) {
            const string sqlStmnt = @"SELECT h.HotelID, h.HotelName, r.HotelRoomID, rt.RoomTypeCode, rt.RoomTypeName FROM Hotel h INNER JOIN HotelRoom r ON r.HotelID = h.HotelID INNER JOIN  RoomType rt ON r.RoomTypeID = rt.RoomTypeID order by h.HotelName, rt.RoomTypeCode";
            var context = new HotelContext();
            var hotelData =  context.Query(sqlStmnt);
            var hotelList = new List<Hotel>();

            //Load our objects
            foreach (dynamic data in hotelData) {
                int hotelID = data.HotelID;
                var hotel = hotelList.Where(h => h.HotelID == hotelID).FirstOrDefault()
                                      ?? new Hotel() {HotelName = data.HotelName};
                hotel.AddRoom(new HotelRoom { HotelRoomID = data.HotelRoomID, RoomType = new RoomType{ TypeCode = data.RoomTypeCode, TypeDescription = data.RoomTypeName}});

                if (hotel.HotelID != 0) {continue;}
                hotel.HotelID = hotelID;
                hotelList.Add(hotel);
            }

            //Display our output
            foreach (var hotel in hotelList) {
                Console.WriteLine("Hotel Name : " + hotel.HotelName + ", Room Count : " + hotel.HotelRooms.Count());
                foreach (var room in hotel.HotelRooms) {
                    Console.WriteLine("--" + room.RoomType.TypeCode + ", " + room.RoomType.TypeDescription);
                }
            }

            Console.ReadLine();
         }
    }

Voici ma base de données.

    public class HotelContext : DynamicModel {
        public HotelContext():base("test") {
        PrimaryKeyField = "HotelID";
        TableName = "Hotel";
        }
    }

Voici les classes que j'ai utilisées. Je n'ai jamais réussi à comprendre à quoi servait votre HotelWithOneRoom.

    public class Hotel{
        private readonly List<HotelRoom> _rooms = new List<HotelRoom>();
        public int HotelID { get; set; }
        public string HotelName { get; set; }
        public void AddRoom(HotelRoom room) {_rooms.Add(room);}
        public IQueryable<HotelRoom> HotelRooms {get {return _rooms.AsQueryable();}}
    }
    public class HotelRoom {
        public int HotelRoomID { get; set; }
        public RoomType RoomType { get; set; }
    }

    public class RoomType {
        public string TypeCode { get; set; }
        public string TypeDescription { get; set; }
    }

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X