엔티티 프레임 워크 linq query Include () 다중 하위 엔티티


176

이것은 정말 기본적인 질문 일 수 있지만 3 수준 (또는 그 이상)에 걸친 쿼리를 작성할 때 여러 하위 엔터티를 포함시키는 좋은 방법은 무엇입니까?

즉, 내가 4 개 테이블이 : Company, Employee, Employee_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를 사용하고 있습니다

답변:


201

확장 방법을 사용하십시오 . 교체 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);

그러나 나는 이것을 다음과 같이 사용하고 싶습니다 : //inside public static class Extensions public static IQueryable<Company> CompleteCompanies(this DbSet<Company> table){ return table .Include("Employee.Employee_Car") .Include("Employee.Employee_Country") ; } //code will be... Company company = context.Companies.CompleteCompanies().FirstOrDefault(c => c.Id == companyID); //same for next advanced method
Hamid

불시 닉스. 확장은 사전 정의 된 기능 확장을위한 첫 번째 호출 포트 여야합니다.
ComeIn

12
몇 년 후, 문자열 기반 포함은 런타임 안전하지 않기 때문에 권장하지 않습니다. 탐색 속성 이름이 변경되거나 철자가 틀리면 끊어집니다. 대신 typed include를 사용하는 것이 좋습니다.
Jeff Putz

2
nameof (class)가 도입되었으므로이 접근 방식을 안전하게 사용할 수 있습니다. 엔터티 이름이 변경되면 컴파일 중에 선택됩니다. 예 : context.Companies.Include (nameof (Employee)) 더 내려 가야 할 경우 nameof (Employee) + "."와 연결되어야합니다. "+ nameof (Employee_Car)
Karl

확장 메소드 기술은 컴파일 된 쿼리 (적어도 EFCore에서는 그렇지 않음)에서 작동하지 않습니다. github.com/aspnet/EntityFrameworkCore/issues/7016
Dunge

156

EF 4.1 ~ EF 6

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 코어

.ThenInclude()구문이 약간 다르지만 EF Core에는 새로운 확장 방법 이 있습니다 .

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

그래서 나는 첫 번째 옵션을 유지하려고합니다 (하나는 잎 엔티티 깊이 모델 당 포함).


4
나는 강하게 타이핑 된 .Include 문으로 어떻게하는지 궁금합니다. Select로 아이들을 영사하는 것이 답이었습니다!

1
"co.Employees.Select (...)"의 내 equiv는 " 'Employees'에 'Select'[또는 extension method]"에 대한 정의가 포함되어 있지 않다는 "Select"구문 오류를 보여줍니다. System.Data.Entity를 포함 시켰습니다. 조인 된 테이블에서 단일 열만 가져오고 싶습니다.
Chris Walsh

1
같은 자식 테이블을 두 번 참조하는 부모 테이블이 있습니다. 이전 문자열 include 구문을 사용하면 올바른 관계를 미리로드하기가 어려웠습니다. 이 방법은 훨씬 더 구체적입니다. 강력한 형식의 포함을 위해 네임 스페이스 System.Data.Entity를 포함해야합니다.
Karl

1
.NET 코어 2.1로 내가 대신 System.Data.Entity의 네임 스페이스 Microsoft.EntityFrameworkCore 필요
denvercoder9

27

codeplex.com 에서이 기사를 찾을 수 있습니다 .

이 기사는 선언적인 그래프 형태로 여러 테이블에 걸쳐있는 쿼리를 표현하는 새로운 방법을 제시합니다.

또한이 기사에는이 새로운 접근 방식과 EF 쿼리의 철저한 성능 비교가 포함되어 있습니다. 이 분석에 따르면 GBQ는 EF 쿼리보다 빠르게 성능이 뛰어납니다.


실제 응용 프로그램에서 어떻게 구현할 수 있습니까?
Victor.Uduak

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.