1

如何在不实际执行查询的情况下延迟加载嵌套列表?使用非常简单的例子,说我有:Linq2Sql - 你如何延迟加载嵌套列表?

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,其中我使用的扩展方法来获得特定的人所拥有的城市街区,说我们只想圭多的块:

GetCityBlocks().ForOwner("Guido") 

如果我们做一个.ToList()在仓库中它要执行查询 - 这将是荒谬的,因为我们不知道我们在那个级别获得的块是谁。所以问题是,我们如何有效地做到这一点?

假设有50000个街区所有者和100万个城市街区,加载它们不是一个选项。使用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 Field对象为IQueryable - 这不看起来是正确的,因为看起来任何访问Cit的人都有太多的权力yBlock.BuildingsOnBlock字段。这是映射到我们的域对象的东西,我们应该可能做的服务层?

+0

整体淘汰的是一个红色的鲱鱼上。诚然,它不会在改进方面得到太多关注,但它已经在框架中,所以它会与我们在一段时间。无论如何,StackOverflow使用Linq to SQL,我会说它工作得很好。 – 2009-08-13 23:49:03

+0

你从GetCityBlocks()方法返回什么?既然你使用扩展过滤器,我猜你已经返回IQueryable了吗?否则你真的应该使用罗伯特的答案。请注意,从存储库中公开IQueryable意味着只公开Linq而不是Linq2Sql – Jaime 2009-08-14 00:09:58

回答

1

您可以通过返回IQueryables而不是ILists来完成。

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

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

目前我找不到引用,但我的理解是,如果你这样做,linq to sql有机会优化它发送给服务器的SQL。换句话说,它最终将读取这些记录:

GetCityBlocks().ForOwner("Guido") 

,而不是这些记录:

GetCityBlocks() 
+0

但是,在域模型中使用IQueryable看起来像是一个问题,因为您只是为DAL执行而这样做,而不是因为它是该域的一部分模型。 IQueryable不一定是查询该对象中的那些字段/属性/类对象所需的东西。还是我仍然不正确地看待这个问题? – MunkiPhD 2009-08-13 23:57:46

+0

我同意你放松控制的一点,但如果我们映射到我们自己的对象在存储库中呢?这是我们应该在别处做什么的吗? (请参阅我的编辑) – MunkiPhD 2009-08-14 00:14:40

0

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

让linq2Sql通过创建自定义数据环境并且不使用设计器进行映射的方式来映射到您的POCO的另一种方式:),这样您可以保持域模型清洁并让linq2Sql在正确的位置填充依赖关系时间。请注意,进入此路线有其自身的问题,但可以完成。

这里有一个链接,让你开始这条路线

Achieving POCO s in Linq to SQL