简体   繁体   English

使用c#检索父/子查询结果SQL Server

[英]Retrieve Parent / Child Query result SQL Server with c#

what I am doing here now is the probably the worst way of fulfilling my requirements but I haven't found any other way. 我现在在这里所做的可能是满足要求的最糟糕的方法,但是我没有找到其他方法。

here is my sample database structure; 这是我的示例数据库结构;

在此处输入图片说明

Here is the script that I use in order to retrieve the certain values; 这是我用来检索某些值的脚本。

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;

Here is the result that the above script is giving me back; 这是上面的脚本还给我的结果;

在此处输入图片说明

everything is fine till here. 一切都很好,直到这里。

I need to move to C# code from here. 我需要从这里转到C#代码。 What I would like to achieve is the following result; 我想要实现的是以下结果;

在此处输入图片说明

Here is where I am worried about. 这是我担心的地方。 I use Linq to achieve this thing and the below code is the code that I used for the above console result. 我使用Linq来实现此目的,下面的代码是我用于上述控制台结果的代码。

    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, if there was a competition on the worst c# code, I would be winning that competition with this code. IMO,如果在最差的C#代码上存在竞争,那么我将用该代码赢得这场竞赛。 (Would I?) (我可以吗?)

So, what is the most optimized way of doing what I do? 那么,做什么是最优化的方法呢?

C# is not my language of choice but here you go: C#不是我选择的语言,但是您可以使用:

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);
}

Like jpmcclung pointed out, you'll need some Software engineering Skills to create successful Applications. 就像jpmcclung指出的那样,您需要具备一些软件工程技能才能创建成功的应用程序。 The bigger your Project, the more design and planning is called for. 您的项目越大,就需要进行更多的设计和计划。

The best way to get around writing code like this is to study up on the practice of test driven design. 避免编写此类代码的最佳方法是研究测试驱动设计的实践。 This code is screaming for it. 这段代码为此大叫。 To see it in action I would check out Brad Wilson's new TDD Full Throttle video at TekPub (http://shop.tekpub.com/products/ft_tdd_wilson) it is 12 bucks but it will be worth it. 要查看它的实际效果,我会在TekPub上查看布拉德·威尔逊的新TDD全油门视频(http://shop.tekpub.com/products/ft_tdd_wilson),它的价格是12美元,但值得。 Otherwise there are numerous resourses on the subject. 否则,在这个问题上有很多资源。

Specifically, why do you need a HotelWithOneRoom? 具体来说,您为什么需要一个HotelWithOneRoom? Just add one room to the Rooms list in a regular hotel. 只需在常规酒店的“房间”列表中添加一个房间即可。 Why don't you override .ToString() on the Hotel and use the StringBuilder to create the output line for a hotel? 为什么不覆盖酒店上的.ToString()并使用StringBuilder创建酒店的输出行? Those are just a few things off the top of my head but if you use TDD it will help organize your design practice and get some of this code out of your way. 这些只是我想不起的几件事,但是如果您使用TDD,它将有助于组织您的设计实践,并摆脱一些代码。

Since you include IQueryable in your example, can we assume that LINQ to SQL or EF is an option for your solution? 由于您在示例中包括IQueryable,因此我们可以假定LINQ to SQL或EF是您的解决方案的一个选择吗? If so, realize that they support projecting into object heirarchies directly. 如果是这样,请意识到他们支持直接投影到对象层次结构中。

Asssuming you have associations set between your tables, it could be as simple as: 假设您在表之间设置了关联,则可能很简单:

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()
             }; 

I think you could start from the beginning here and avoid some confusion by renaming your Tables. 我认为您可以从头开始,并通过重命名表来避免造成混淆。 I think your table names should be Hotel, Room and RoomType (I'm not a fan of pluralized table names, but that's beside the point). 我认为您的表名应该是Hotel,Room和RoomType(我不赞成使用多个表名,但是这很重要)。

To think in 'Domain' terms, you have a Hotel. 用“域”的术语来思考,您有一家酒店。 A hotel has Rooms. 一个酒店有房间。 Each room is defined as a type of room, Double, Single, etc... 每个房间被定义为房间类型,双人间,单人间,等等。

Anyway, I threw some code together that's doing the same thing yours is doing. 无论如何,我将一些代码放在一起,它们的功能与您的代码相同。 It's a little clearer I think. 我认为这要清楚一点。 For database access, I used Massive https://github.com/robconery/massive because it's quick and fun. 对于数据库访问,我使用了Massive https://github.com/robconery/massive,因为它既快速又有趣。

Anyway, here is the code I came up with. 无论如何,这是我想出的代码。

    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();
         }
    }

Here is my Database stuff. 这是我的数据库资料。

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

Here are the classes I used. 这是我使用的类。 Couldn't ever figure out what your HotelWithOneRoom was meant for. 永远无法弄清楚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; }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM