【问题标题】:Eager-loaded related objects which are null are being lazy-loaded急切加载的空相关对象正在延迟加载
【发布时间】:2012-07-25 06:33:08
【问题描述】:

我急切地加载(通过使用 .Include())相关实体,以尽量减少为特别“海量”数据网格生成的 SQL 查询的数量。在 POCO 中,相关实体是公共虚拟导航属性,这意味着它们是延迟加载的。我想保留延迟加载这些相关实体的默认行为,因为它最适合我项目的其他部分。

现在,在预先加载相关实体之后,我可以看到仍然有相当数量的查询生成。这是仅针对相关实体的查询为空(空只是因为 sql 连接“发现”没有相关数据)。

这让我相信,当我稍后在表示层中访问这些实体时,EF 会尝试延迟加载这些实体(认为它们尚未加载)。

我是否遗漏了一些基本的东西,或者有什么办法可以解决这个问题?

示例代码
使用存储库模式,这里有一些简化的方法(省略分页、排序、过滤等)。

通用存储库中的获取方法

public IEnumerable<T> Get(
    Expression<Func<T, object>>[] includes = null)
{
    IQueryable<T> query = set;

    ...

    // Include properies for eager loading
    if (includes != null)
    {
       query = includes.Aggregate(query, 
          (current, include) => current.Include(include));
    }

    ...

    return query.ToList();
}

上面是从服务类调用的,类似这样的

...
context.Licenses.Get(
    includes: new Expression<Func<License, object>>[] { l => l.Comment }
);
...

授权 POCO

public class License
{
    public License()
    {
    }

    // Primitive properties
    public string ID { get; set; }
    public string Name { get; set; }
    ...
    // Navigation properties
    public virtual LicenseComment Comment { get; set; }
    ...
}

许可证评论 POCO

public class LicenseComment
{
    public LicenseComment()
    {
    }

    // Primitive properties
    public string LicenseID { get; set; }
    public string Comment { get; set; }
}

在 MVC Razor 视图(或为此而在模型中)访问属性

<span>@license.Comment</span>


每当我尝试访问一个为 null 的 License.Comment(通过 SQL Server Profiler 查找)时,都会生成额外的 SQL 查询,在我看来,实体框架延迟加载会启动,即使我急切地包含了这个属性。

【问题讨论】:

  • 能否贴出相关代码。
  • 当然,我已经更新了帖子。

标签: asp.net-mvc-3 entity-framework poco eager-loading


【解决方案1】:

我无法尝试知道,但我希望这不应该发生。无论如何,如果您有一个不希望发生延迟加载的页面,您可以简单地关闭该页面:

context.Configuration.LazyLoadingEnabled = false;

或者您可以为这些查询关闭代理创建 - 未代理的实体不能使用延迟加载:

context.Configuration.ProxyCreationEnabled = false;

【讨论】:

    【解决方案2】:

    我同意@Ladislav 的观点,认为它不应该发生,并测试了“正常”行为如下:

    如果您加载包含评论的许可证...

    var license = context.Licenses.Include(l => l.Comment).Single(l => l.ID == 1);
    

    ...EF 将导航属性标记为已加载:

    var isCommentLoaded = context.Entry(license).Reference(l => l.Comment).IsLoaded;
    

    无论评论是null还是不是isCommentLoaded都会是true,访问Comment属性时不会发出延迟加载查询。

    即使你不使用预加载...

    var license = context.Licenses.Single(l => l.ID == 1);
    

    ...isCommentLoaded 将是 true 如果 从许可证到数据库中评论的外键是 NULL(但如果外键不是,它将是 false NULL)。原因是 EF 总是将 SELECT 语句中的外键加载到上下文中,如果这个键是 NULL EF 知道数据库中没有相关的注释并将导航属性标记为已加载以避免不必要的懒惰正在加载。

    【讨论】:

    • 感谢您的确认。您所描述的正是我认为应该发生的事情 - 即 EF 为导航属性保持加载状态。看起来我需要更彻底地测试这一点,尤其是使用 Reference().IsLoaded 和实际的关联设置,即使看起来不错。最后的手段是@Ladislav 的建议,但这不是必须的!
    【解决方案3】:

    虽然不完全是您的情况,但我有类似的情况,我指出有一个额外的属性访问不是原始包含的一部分。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-09-30
      • 1970-01-01
      • 1970-01-01
      • 2011-03-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多