使用实体框架和查询而不创建大量查询(避免N + 1)

时间:2011-05-14 12:42:33

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

我一直在使用一种设计模式,在使用Entity Framework Profiler之后,它看起来可能非常愚蠢。

我已经扩展了我的实体类,使其属性是与该实体关联的集合的过滤视图。像这样:

public IEnumerable<Member> ActiveMembers
{
    get
    {
        return Members.Where(t => t.LeftDate == null);
    }
}

由于我对那些没有离开俱乐部的成员感兴趣,这个属性非常有用,似乎有意义。

但是,从运行EF Profiler开始,我现在知道这通常会导致N + 1问题。如果我遍历成员并且还想显示他们的地址,那么每个地址请求都会导致额外的数据库查询。

我从question I asked知道我可以将我的财产修改为:

return Members.CreateSourceQuery().Include("Address")
              .Where(t => t.LeftClubDate == null);

在这种情况下,这将摆脱N + 1问题,但我并不总是想要地址信息,我可能想要跟随会员的另一个导航属性。

理想情况下,我希望能够保持我的过滤属性(如ActiveMembers)的灵活性,并能够在之后决定要在查询中包含哪些属性。像这样:

var membersToDisplay = ActiveMembers.Include("Address").ToList();

这是可能的,还是我需要修改过滤后的属性想法?

1 个答案:

答案 0 :(得分:3)

不,无法在Include上致电IEnumerableIncludeObjectQuery / DbQuery的一项功能。可以在Include上调用IQueryable(使用EFv4.1或自定义扩展),但它仍然在内部将传递的查询转发给ObjectQueryDbQuery,如果强制转换则不会抛出异常完成。您必须重新设计您的应用程序。

  

我并不总是想要这个地址   信息,我可能想跟随   另一个导航属性   构件。

您必须根据当前需求填写数据或使用N + 1问题。例如,您可以使用单独的linq查询:

var clubId = ActiveClub.Id;
var members = (from member in context.Members.Include("Address")
               where member.LeftDate == null and member.ClubId == clubId
               select member).ToList();