views:

39

answers:

1

I am trying to optimize a LINQ to SQL request so that it results in a single SQL statement. At the moment i have something like this:

EDIT : removed the "where" filter for clarity - also "Id" is a primary key in the databsse for both object types

hotel = (from h in db.Hotels

         let rooms = (from r in db.HotelRooms
                      where r.HotelId == h.Id
                      select new HotelRoom
                      {
                          Id = r.Id,
                          Code = r.Code,
                          Category = r.Category
                      })

         select new Hotel
         {
             Id = h.Id,
             Name = h.Name,
             Rooms = rooms.ToList()
         }).FirstOrDefault();

Where the Hotel business level class is defined as:

public class Hotel
{
    public int Id { get; set; }
    public string Name { get; set; }
    public List<HotelRoom> Rooms { get; set; }
}

Wherein the query is using initializers to create business objects on the fly from the DataContext entities as the query is executed.

The problem is that obviously the .ToList() on the Rooms collection causes the Hotel.Rooms collection to be populated via a second query.

Is there a way to populate the Hotel.Rooms property with all the HotelRooms, without it generating additional queries?

A: 
  //grab the rows from the database in direct fashion.
var joinedRows = 
(
  from h in db.Hotels
  where h.Name == name
  from hr in h.HotelRooms
  select new {HotelRow = h, HotelRoomRow = hr}
)
.ToList();

  //shape the data locally
List<Hotel> result =
  from row in joinedRows
  group row.HotelRoomRow by row.HotelRow into g
  let h = g.Key
  select new Hotel()
  {
    Id = h.Id,
    Name = h.Name,
    Rooms = (
      from r in g
      select new HotelRoom()
      {
        Id = r.Id,
        Code = r.Code,
        Category = r.Category
      }).ToList()
  };
David B
Thanks - but this seems to return 1 Hotel with 1 HotelRoom, for each HotelRoom in the database. So if there are 10 hotels, with 10 rooms each - this returns 100 Hotel items with 1 Room each.
krisg
Sorry - just to clarify something - i changed the above code removing the "name ==" condition to retrieve ALL hotels rather than a specific one. That's why it's returning all hotels in the database. That's not the problem i was bringing up - the problem is still that it returns 1 hotel object for every hotelroom - with each hotel object only having 1 room.
krisg
the "shape the data locally" part resolves that.
David B
Well when i tried that exact code in a test console app - it didn't. I had it print a line for each hotel - with the number of rooms in that hotel. It printed 1500 lines, equal to the number of rooms in total, instead of 279, the number of hotels - and each hotel had only 1 room in - nistead of displaying the 4-10 rooms it should of had.
krisg
Do you have a primary key for your Hotels? Without a primary key, this code won't work.
David B
Yes - primary key is the ID.
krisg
Question modified to indicate that ID's are primary keys
krisg