How do you lazy load nested lists without actually executing the query? Using a very basic example, say I have:
class CityBlock {
IList<Building> BuildingsOnBlock;
Person BlockOwner;
}
class Building {
IList<Floor> FloorsInBuilding;
}
class Floor {
IList<Cubicle> EmployeeCubicles;
}
Class Cubicle {
System.Guid CubicleID;
Person CubicleOccupant;
}
And then in my repository layer, I have the following method:
GetCityBlocks()
And then in the Service layer I'll have GetCityBlocksByOwner, where I utilize an extension method to get the city blocks owned by a specific person, say we just want Guido's blocks:
GetCityBlocks().ForOwner("Guido")
If we do a .ToList() in the repository it's going to execute the queries - that's going to be ridiculous since we don't know who's blocks we're getting at that level. So the question is, how do we do this efficiently?
Let's assume there are 50000 block owners, and some 1000000 city blocks, loading all of them is not an option. Using IQueryables won't work due to the nesting (without extreme hacking, at least that I'm aware of). Also, if I try to use something like Rob Conery's LazyList, then we essentially have a leak from our DAL into our domain models, which could be very very bad in the future.
So how do I go about doing this correctly?
- Is it a matter of determining the correct context? If so, would we do this in the Repository Layer, or the Service layer?
- Do I half meld together the Service layer and my Repository layer to get very specific service methods?
- Or am I missing something entirely? (still relatively new to the Linq2Sql thing, which is being phased out anyways so...)
Edit: In the repository pattern, we're currently mapping to our domain objects, so it would look something like this:
public IQueryable<CityBlock> GetCityBlocks(){
var results = from o in db.city_blocks
let buildings = GetBuildingsOnBlock(o.block_id)
select new CityBlock {
BuildingsOnBlock = buildings,
BlockOwner = o.block_owner
};
return results;
}
For this to work, we'd have to make the buildings get a .ToList(), unless we make that actual field in the CityBlock object an IQueryable - which doesn't seem right, because it seems as if too much power would be granted to anyone who accesses the CityBlock.BuildingsOnBlock field. Is this mapping to our domain objects something we should maybe do up in the service layer?