【发布时间】:2010-11-19 12:05:15
【问题描述】:
如何在不实际执行查询的情况下延迟加载嵌套列表?使用一个非常基本的示例,假设我有:
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 基本上会泄漏到我们的域模型中,这在未来可能会非常糟糕。
那么我该如何正确地做到这一点呢?
- 是否确定 正确的上下文?如果是这样,我们会这样做 this 在存储库层中,或 服务层?
- 我是否将服务层和我的存储库层半融合在一起以获得 非常具体的服务方式?
- 还是我完全遗漏了什么? (对于 Linq2Sql 来说还是比较新的 正在被淘汰的东西 无论如何……)
编辑: 在存储库模式中,我们目前正在映射到我们的域对象,所以它看起来像这样:
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 字段的任何人。这种映射到我们的领域对象是我们应该在服务层中做的吗?
【问题讨论】:
-
整个淘汰的事情是一个红鲱鱼。虽然它确实不会在改进方面引起太多关注,但它已经在框架中,所以它会伴随我们一段时间。无论如何,StackOverflow 使用 Linq to SQL,我会说它工作得很好。
-
您从 GetCityBlocks() 方法返回了什么?由于您使用的是扩展过滤器,我猜您已经返回 IQueryable 对吗?否则你真的应该使用罗伯特的答案。请注意,从您的存储库中公开 IQueryable 意味着只公开 Linq 而不是 Linq2Sql
标签: .net linq-to-sql repository-pattern lazy-loading service-layer