1

如何在不实际执行查询的情况下延迟加载嵌套列表?使用一个非常基本的示例,假设我有:

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 基本上会泄漏到我们的域模型中,这在未来可能会非常非常糟糕。

那么我该如何正确地做到这一点呢?

  • 这是确定正确上下文的问题吗?如果是这样,我们会在存储层或服务层中这样做吗?
  • 我是否将服务层和存储库层半融合在一起以获得非常具体的服务方法?
  • 还是我完全错过了什么?(对于 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 字段的任何人。这个映射到我们的领域对象是我们应该在服务层做的吗?

4

2 回答 2

1

您可以通过返回 IQueryables 而不是 ILists 来做到这一点。

ToList() 使查询立即执行,因为必须执行从 IQueryable 到 IList 的转换。

只要您返回 IQueryables,延迟加载就应该推迟执行,直到实际需要数据,即调用 ToList() 时。

目前我找不到参考资料,但据我了解,如果您这样做,linq to sql 有机会优化它发送到服务器的 SQL。也就是说,它最终会读取这些记录:

GetCityBlocks().ForOwner("Guido")

而不是这些记录:

GetCityBlocks()
于 2009-08-13T23:44:01.920 回答
0

您可以尝试不同的方法来映射您的域对象以使其工作。问题是,无论您做什么(除非您将列表更改为域对象中的 IQueryables),您在映射时都会以 ToList() 结束。

另一种方法是让 linq2Sql 通过创建自定义数据上下文而不使用设计器进行映射来映射到您的 POCO :),这样您就可以保持域模型的清洁并让 linq2Sql 在正确的时间填充依赖项。请注意,进入这条路线有其自身的问题,但可以做到。

这是一个链接,可让您开始这条路线

在 Linq to SQL 中实现 POCO

于 2009-08-14T00:40:09.273 回答