禁用延迟加载是危险的?

时间:2014-12-19 13:05:50

标签: entity-framework

我有一个ASP.NET MVC应用程序,它利用实体框架来处理数据层。

在我的一种方法中,我检索产品的季节性可用性数据,然后检索产品的最佳税率。

public ProductList FetchProductSearchList(ProductSearchCriteria criteria)
{
    ...
    var avail = ProductAvailabilityTemplate.Get(criteria.ProductID);
    ...
    var tr = TaxRate.BestMatchFor(criteria.ProductID, criteria.TaxCode);
    ...
}

在ProductAvailabilityTemplate.Get的数据层中,我一直在优化LINQ代码的性能。特别是,我设置ctx.ObjectContext.ContextOptions.LazyLoadingEnabled = false;以防止EF加载某些实体(通过导航属性),在这种情况下我不需要。

但是,一旦进行了此更改,我发现我的TaxRates未完全加载,因为我的Tax数据层代码中的ctx.ObjectContext.ContextOptions.LazyLoadingEnabled仍为false。这意味着没有加载通过导航属性链接到TaxRate的实体。

要解决这个问题,我只需在Tax数据层方法中设置ctx.ObjectContext.ContextOptions.LazyLoadingEnabled = true;,但我担心无关的更改可能会导致这样的问题。您似乎无法安全地禁用一个功能的延迟加载,而不会影响之后调用的操作。我很想删除所有的导航属性,禁用延迟加载,并使用良好的老式连接来加载我需要的每个数据层调用,不多也不少。

欢迎任何建议。

2 个答案:

答案 0 :(得分:2)

当我开始使用EF时,我喜欢延迟加载,但过了一段时间后,我意识到它影响了性能,因为它有效地禁用了连接并在单独的查询中提取所有子数据,即使您需要一次性使用它。 / p>

所以现在我宁愿使用Includes来热切地加载我感兴趣的子实体。你也可以这样做有点动态,例如提供 includeDetails 参数:

public IEnumerable<Customer> LoadCustomersStartingWithName(string name, bool includeDetails)
{
    using (var db = new MyContext())
    {
        var customers = db.Customers;
        if (includeDetails)
            customers = customers.Include(x => x.Orders).Include(x => x.ContactPersons);

        customers = customers.Where(x => x.Name.StartsWith(name));

        return customers;        
    }
}

要使代码在EF6中运行,您还需要包含

using System.Data.Entity;

位于班级的顶部

答案 1 :(得分:2)

这是一种权衡:

延迟加载

  • 为您提供了无需在加载期间指定图表深度的好处
  • 将需要返回数据库以检索缺少的结果
  • 要求对POCO进行一些污染(例如virtual属性与代理)
  • 要求DbContext在所有数据访问期间保持更长时间。

急切加载

  • 在每次获取期间需要更深入地考虑加载深度
  • 通常会生成较少的查询,使用更宽的连接来一次获取图表
  • 不需要对您的实体进行任何更改或仪式
  • 允许更短的连接和DbContexts

FWIW,我通常在启用了延迟加载的情况下完成原型工作,使软件处于可证明状态,一旦数据访问模式稳定,然后关闭延迟加载并明确移动到Include d引用。检查空引用的一些单元测试在这一点上也会产生奇迹。我不愿意提供仍然启用了延迟加载的生产系统,因为存在一个非确定性元素(例如难以完全测试),并且需要返回数据库以获取更多数据会损害性能。

无论哪种方式,我都不会关闭所有导航并进行显式连接 - 您正在失去ORM提供的导航功能。当您退出延迟加载时,只需使用适用的Includes明确定义要加载的实体