實體框架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);

所以我會繼續使用第一個選項(每個實體深度模型包含一個)。



Related

許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因
許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因