代码之家  ›  专栏  ›  技术社区  ›  MunkiPhD

Linq2Sql-如何延迟加载嵌套列表?

  •  1
  • MunkiPhD  · 技术社区  · 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 Conry的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字段的人都会被授予过多的权限。这种到域对象的映射是我们在服务层应该做的吗?

    2 回复  |  直到 15 年前
        1
  •  1
  •   Robert Harvey    15 年前

    您可以通过返回IQueryables而不是ILists来实现。

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

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

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

    GetCityBlocks().ForOwner("Guido")
    

    GetCityBlocks()
    
        2
  •  0
  •   Jaime    15 年前

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

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

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

    Achieving POCO s in Linq to SQL