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

entity-framework lazy-loading linq

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

即我有4个表: CompanyEmployeeEmployee_CarEmployee_Country

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

Employee与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

一般承认的答案

使用扩展方法 。将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);

热门答案

EF 4.1至EF 6

有一个强类型.Include ,它允许通过将Select表达式提供到适当的深度来指定所需的.Include加载加载深度:

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写了一个小例子

EF核心

EF Core有一个新的扩展方法.ThenInclude() ,虽然语法略有不同

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

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

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

多个孙子加载可以在一个步骤中完成,但这需要在向下移动下一个节点之前备份相当笨拙的反转(NB:这不适用于AsNoTracking() - 您将得到运行时错误):

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

所以我会继续使用第一个选项(每个实体深度模型包含一个)。




许可下: CC-BY-SA with attribution
不隶属于 Stack Overflow
这个KB合法吗? 是的,了解原因
许可下: CC-BY-SA with attribution
不隶属于 Stack Overflow
这个KB合法吗? 是的,了解原因