【问题标题】:Using Entity Framework and where queries without creating lots of queries (avoiding N+1)使用实体框架和 where 查询而不创建大量查询(避免 N+1)
【发布时间】:2011-08-25 12:07:57
【问题描述】:

我一直在使用一种设计模式,在使用 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 问题,但我并不总是想要地址信息,我可能想要关注 Member 的另一个导航属性。

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

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

这可能吗,还是我需要重新考虑过滤属性的想法?

【问题讨论】:

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


    【解决方案1】:

    不,不能在IEnumerable 上调用IncludeIncludeObjectQuery / DbQuery 的特征。可以在 IQueryable 上调用 Include(使用 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();
    

    【讨论】:

    • 感谢您的帮助。看来我需要重新设计一些东西。
    猜你喜欢
    • 2011-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-29
    • 2015-04-26
    • 1970-01-01
    • 2011-06-29
    相关资源
    最近更新 更多