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

问题描述:

这可能是一个真正的元素问题,但是在编写跨越三个级别(或更多)的查询时包含多个子实体的最好方法是什么?实体框架linq查询包含()多个子实体

即我有4个表:CompanyEmployeeEmployee_CarEmployee_Country

公司具有1:与雇员米关系。

员工与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

我使用EF4 VS 2010中

使用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); 
+5

这太棒了。 – 2013-03-20 18:32:17

+0

但我想用它这个像:'//内公共静态类扩展 公共静态的IQueryable CompleteCompanies(这DbSet 表){ 返回表 .INCLUDE(“Employee.Employee_Car”) .INCLUDE(” Employee.Employee_Country“); } // code将... Company company = context.Companies.CompleteCompanies()。FirstOrDefault(c => c.Id == companyID); //下一个高级方法相同 – Hamid 2016-03-28 08:28:20

+0

Bullsye Nix。扩展应该是...的第一个端口,以及扩展预定义的功能。 – ComeIn 2016-04-23 10:29:21

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(); 
... 

您可能会发现这篇文章的兴趣是可以在codeplex.com

本文提出了一种表达查询的新方法,该方式以声明图形形式跨越多个表。

此外,该文章包含了这种新方法与EF查询的全面性能比较。该分析表明GBQ快速超过EF查询。

+1

非常有趣的文章! – 2015-04-27 07:46:55

EF 4.1至EF 6

有一个strongly typed .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 here

EF核心

EF核心有一个新的扩展方法,.ThenInclude(),虽然语法是slightly different

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

按的文档,我将保留额外的'缩进'.ThenInclude以保持您的理智。

过时的信息(别这样做):

的多个孙子加载可以在一个步骤中完成,但是这需要一个比较尴尬的逆转回升图表标题下的下一个节点之前(注:这不会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); 

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

+3

我想知道如何用强类型.Include语句来完成它。用Select来展示孩子就是答案! – 2015-05-13 13:19:13

+6

感谢您添加命名空间! – GRGodoi 2016-07-04 20:04:38

+1

我的“co.Employees.Select(...)”等号在“Select”中显示语法错误,并说“'Employees'不包含'Select'[或扩展方法]的定义”。我已经包含了System.Data.Entity。我只想从连接表中获取单个列。 – 2017-01-17 09:55:31