2010-07-28 184 views
131

這可能是一個真正的元素問題,但是在編寫跨越三個級別(或更多)的查詢時包含多個子實體的最好方法是什麼?實體框架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中

回答

163

使用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

91

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