【问题标题】:Using Entity Framework navigation properties without creating lots of queries (avoiding N+1)使用实体框架导航属性而不创建大量查询(避免 N+1)
【发布时间】:2011-08-25 06:55:20
【问题描述】:

我一直在使用 Entity Framework Profiler 来测试我在 MVC 项目中的数据访问,并且由于 N+1 问题,我在多个页面中进行的数据库查询远远超出了我的需要。

这是一个简单的例子来说明我的问题:

var club = this.ActiveClub; // ActiveClub uses code similar to context.Clubs.First() 
var members = club.Members.ToList();
return View("MembersWithAddress", members);

视图循环遍历成员,然后遵循每个成员的导航属性以显示他们的地址。每个地址请求都会导致额外的数据库查询。

解决此问题的一种方法是使用 Include 来确保预先查询我需要的额外表。但是,我似乎只能在直接附加到上下文的俱乐部 ObjectSet 上执行此操作。在这种情况下,ActiveClub 属性由许多控制器共享,我并不总是想预先查询成员和地址表。

我希望能够使用类似的东西:

var members = club.Members.Include("Address").ToList();

但是,Members 是一个 EntityCollection,它没有 Include 方法。

有没有办法强制加载 Members EntityCollection 并要求 EF 也加载他们的地址?

或者,以这种方式在实体上使用 EntityCollection 导航属性,这是一个非常糟糕的主意;当你从上下文中获取它时,你应该知道你正在加载什么?

【问题讨论】:

    标签: entity-framework entity-framework-4 navigation-properties select-n-plus-1


    【解决方案1】:

    如果您的实体继承自 EntityObject,请尝试使用:

    var members = club.Members.CreateSourceQuery()
                              .Include("Address")
                              .ToList();
    

    如果您使用带有延迟加载代理的 POCO,请尝试使用:

    var members = ((EntityCollection<Club>)club.Members).CreateSourceQuery()
                                                        .Include("Address")
                                                        .ToList();
    

    显然第二个版本不是很好,因为 POCO 用于消除对 EF 的依赖,但现在您需要将集合转换为 EF 类。另一个问题是查询将被执行两次。延迟加载将触发Members 一次访问该属性,然后在您调用ToList 时执行第二次查询。这可以在运行查询之前通过turning off lazy loading 解决。

    当您说ActiveClub 是共享的时,我相信这意味着它是派生控制器中使用的基本控制器中的属性。在这种情况下,您仍然可以在不同的控制器中使用不同的代码来填充属性。

    【讨论】:

    • 谢谢。这非常有效。我仍然可以做很多事情来减少查询数量,但这是造成最大打击的一个。
    猜你喜欢
    • 2011-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多