如何在不实际执行查询的情况下延迟加载嵌套列表?使用一个非常基本的例子,说我有:
class CityBlock {
IList<Building> BuildingsOnBlock;
Person BlockOwner;
}
class Building {
IList<Floor> FloorsInBuilding;
}
class Floor {
IList<Cubicle> EmployeeCubicles;
}
Class Cubicle {
System.Guid CubicleID;
Person CubicleOccupant;
}
然后在我的存储库层中,我有以下方法:
GetCityBlocks()
然后在服务层我将拥有GetCityBlocksByOwner,我使用扩展方法来获取特定人拥有的城市街区,比如说我们只想要Guido的街区:
GetCityBlocks().ForOwner("Guido")
如果我们在存储库中执行.ToList(),它将执行查询 - 这将是荒谬的,因为我们不知道我们在该级别获得了哪些阻止。所以问题是,我们如何有效地做到这一点?
假设有50000个区块所有者,以及大约1000000个城市区块,加载所有区块都不是一个选项。使用IQueryables将无法工作,因为嵌套(没有极端的黑客攻击,至少我知道)。另外,如果我尝试使用Rob Conery的LazyList之类的东西,那么我们基本上会从DAL泄漏到我们的域模型中,这可能会在将来非常糟糕。
那么我该如何正确地做到这一点?
修改 在存储库模式中,我们当前正在映射到我们的域对象,所以它看起来像这样:
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;
}
为了实现这一点,我们必须让建筑物得到.ToList(),除非我们将CityBlock对象中的实际字段设为IQueryable - 这似乎不对,因为它看起来好像太多了任何访问CityBlock.BuildingsOnBlock字段的人都可以获得权力。这是映射到我们的域对象我们应该在服务层中做什么吗?
答案 0 :(得分:1)
你可以通过返回IQueryables而不是IList来实现。
ToList()会导致查询立即执行,因为必须从IQueryable到IList执行转换。
只要你返回IQueryables,延迟加载应该推迟执行,直到实际需要数据,即调用ToList()时。
我目前找不到引用,但我的理解是,如果你这样做,linq to sql有机会优化它发送给服务器的SQL。换句话说,它最终会读取这些记录:
GetCityBlocks().ForOwner("Guido")
而不是这些记录:
GetCityBlocks()
答案 1 :(得分:0)
您可以尝试使用不同的方法映射域对象以使其正常工作。问题在于,无论您做什么(除非您将列表更改为域对象中的IQueryables),您将在映射时结束ToList()。
让linq2Sql通过创建自定义datacontext并且不使用设计器进行映射来让映射到POCO的另一种方式,这样就可以保持域模型的清洁,并让linq2Sql在正确的时间填充依赖项。请注意,进入此路线有其自身的问题,但可以这样做。
这是一个让你开始这条路线的链接