实体框架linq查询Include()多个子实体

时间:2010-07-28 19:15:00

标签: linq entity-framework lazy-loading

这可能是一个非常重要的问题但在编写跨越三个级别(或更多)的查询时,包含多个子实体的好方法是什么?

即。我有4个表:CompanyEmployeeEmployee_CarEmployee_Country

公司与员工有1:m的关系。

员工与Employee_Car和Employee_Country的关系为1:m。

如果我想编写一个返回所有4个表中数据的查询,我现在写的是:

Company company = context.Companies
                         .Include("Employee.Employee_Car")
                         .Include("Employee.Employee_Country")
                         .FirstOrDefault(c => c.Id == companyID);

必须有一个更优雅的方式!这是冗长的,并产生可怕的SQL

我在VS 2010中使用EF4

5 个答案:

答案 0 :(得分:187)

使用extension methods。 将 NameOfContext 替换为对象上下文的名称。

public static class Extensions{
   public static IQueryable<Company> CompleteCompanies(this NameOfContext context){
         return context.Companies
             .Include("Employee.Employee_Car")
             .Include("Employee.Employee_Country") ;
     }

     public static Company CompanyById(this NameOfContext context, int companyID){
         return context.Companies
             .Include("Employee.Employee_Car")
             .Include("Employee.Employee_Country")
             .FirstOrDefault(c => c.Id == companyID) ;
      }

}

然后您的代码变为

     Company company = 
          context.CompleteCompanies().FirstOrDefault(c => c.Id == companyID);

     //or if you want even more
     Company company = 
          context.CompanyById(companyID);

答案 1 :(得分:139)

EF 4.1至EF 6

strongly typed .Include允许通过将Select表达式提供到适当的深度来指定所需的预先加载深度:

using System.Data.Entity; // NB!

var company = context.Companies
                     .Include(co => co.Employees.Select(emp => emp.Employee_Car))
                     .Include(co => co.Employees.Select(emp => emp.Employee_Country))
                     .FirstOrDefault(co => co.companyID == companyID);

在两个实例中生成的Sql仍然不是直观的,但似乎足够高效。我在GitHub here

上加了一个小例子

EF Core

EF Core有一种新的扩展方法.ThenInclude(),但语法为slightly different

var company = context.Companies
                     .Include(co => co.Employees)
                           .ThenInclude(emp => emp.Employee_Car)
                      ...

根据文档,我会在.ThenInclude中保留额外的“缩进”以保持理智。

过时信息(不要这样做):

加载的多个孙子可以一步完成,但这需要在向下移动下一个节点之前备份相当尴尬的逆转(注意:这不适用于{{1} } - 你会得到一个运行时错误):

AsNoTracking()

所以我会留下第一个选项(每个叶子实体深度模型包含一个)。

答案 2 :(得分:27)

您可能会在codeplex.com找到感兴趣的文章。

本文介绍了一种表达查询的新方法,这些查询以声明图形的形式跨越多个表。

此外,本文还包含对这种新方法与EF查询的全面性能比较。该分析表明GBQ快速优于EF查询。

答案 3 :(得分:4)

How do you construct a LINQ to Entities query to load child objects directly, instead of calling a Reference property or Load()

除了实现延迟加载外,别无他法。

或手动加载......

myobj = context.MyObjects.First();
myobj.ChildA.Load();
myobj.ChildB.Load();
...

答案 4 :(得分:0)

可能会帮助某人,每个级别上有4个级别和2个孩子

Library.Include(a => a.Library.Select(b => b.Library.Select(c => c.Library)))
            .Include(d=>d.Book.)
            .Include(g => g.Library.Select(h=>g.Book))
            .Include(j => j.Library.Select(k => k.Library.Select(l=>l.Book)))