엔터티 프레임 워크-여러 수준의 속성 포함


376

Include () 메서드는 객체의 목록에 매우 적합합니다. 하지만 두 단계 더 깊이 가야한다면 어떻게해야합니까? 예를 들어, 아래 메소드는 여기에 표시된 특성이 포함 된 ApplicationServer를 리턴합니다. 그러나 ApplicationsWithOverrideGroup은 다른 복잡한 개체를 보유하는 또 다른 컨테이너입니다. 해당 속성에 대해 Include ()를 수행 할 수 있습니까? 또는 해당 속성을 완전히로드하려면 어떻게해야합니까?

현재이 방법은 다음과 같습니다.

public IEnumerable<ApplicationServer> GetAll()
{
    return this.Database.ApplicationServers
        .Include(x => x.ApplicationsWithOverrideGroup)                
        .Include(x => x.ApplicationWithGroupToForceInstallList)
        .Include(x => x.CustomVariableGroups)                
        .ToList();
}

Application 또는 CustomVariableGroup 속성 (아래)이 아닌 Enabled 속성 (아래) 만 채 웁니다. 어떻게하면 되나요?

public class ApplicationWithOverrideVariableGroup : EntityBase
{
    public bool Enabled { get; set; }
    public Application Application { get; set; }
    public CustomVariableGroup CustomVariableGroup { get; set; }
}

안녕하세요, Expression must be a member expression이것을 시도 할 때 예외가 발생 하는 이유 는 다음과 같습니다 query.Include(e => e.Level1Collection.Select(l1 => l1.Level2Collection)).
Joe.wang

1
@BobHorn, 나는 같은 문제가 있습니다 .. 내 경우에는 중첩이 여러 계층으로 내려갑니다. 생성 된 SQL에서 모든 열이 c1, c2와 같은 다른 별칭 이름으로 반환되는 것을 볼 수 있습니다. 내 질문은, 내 모든 포함에서 중첩 된 DTO 컬렉션을 형성하는 방법입니다. )
TechQuery

답변:


703

EF 6

using System.Data.Entity;

query.Include(x => x.Collection.Select(y => y.Property))

람다에 필요한 using System.Data.Entity;버전을 얻으려면 추가해야합니다 Include.


EF 코어

새로운 방법을 사용하십시오 ThenInclude

query.Include(x => x.Collection)
     .ThenInclude(x => x.Property);

1
ApplicationsWithOverrideGroup에서 Include ()를 수행 할 수 없습니다. 지능적으로 표시되지 않습니다.
밥 혼

ApplicationsWithOverrideGroup이 목록이므로 편집을 사용할 수 없습니다. 응용 프로그램은 목록 자체가 아니라 목록의 각 항목에 대한 속성입니다.
밥 혼

1
아아,하지만 당신이 제공 한 그 링크가 답을 제공하는 것 같습니다. 이것을 시도해 봅시다 : 컬렉션을 포함시키고 컬렉션을 한 레벨 아래로 포함 시키려면 : query.Include (e => e.Level1Collection.Select (l1 => l1.Level2Collection)).
밥 혼

60
용도에 System.Data.Entity를 포함시켜야합니다. 그렇지 않으면 Intellisense는 메소드의 Include (string path) 버전 만 제공합니다.
OJ Raqueño

5
@ Include각 자산에 대해 전화해야 합니다 :Db.States.Include(state => state.Cities.Select(city => city.Customers).Include(state => state.Cities.Select(city => city.Vendors)
Diego Torres

72

올바르게 이해하면 중첩 속성을 포함시키는 것이 좋습니다. 그렇다면 :

.Include(x => x.ApplicationsWithOverrideGroup.NestedProp)

또는

.Include("ApplicationsWithOverrideGroup.NestedProp")  

또는

.Include($"{nameof(ApplicationsWithOverrideGroup)}.{nameof(NestedProp)}")  

6
고마워, 나는 그것을 시도 할 수 있습니다. 나는 물건을 강력하게 타이핑하고 문자열 리터럴을 피할 수 있기를 바랐습니다. 그러나 그것이 그렇게된다면 ...
Bob Horn

1
당신은 가까이있었습니다. ApplicationsWithOverrideGroup이 목록인지 확실하지 않을 수 있습니다. 도움을 주셔서 감사합니다!
밥 혼

@ Judo, 나는 같은 문제가 있습니다 .. 내 경우에는 중첩이 여러 계층으로 내려갑니다. 생성 된 SQL에서 모든 열이 c1, c2와 같은 다른 별칭 이름으로 반환되는 것을 볼 수 있습니다. 내 질문은 내 모든 포함에서 중첩 된 DTO 컬렉션을 구성하는 방법입니다. (.. 사용자 지정 DTO없이 모든 열을 반환한다는 점에서 위의 예제 자체를 취할 수 있습니까 (DTO의 컬렉션 임) )
TechQuery

2
용도에 System.Data.Entity 를 포함 시켜야합니다. 그렇지 않으면 Intellisense는 Include(string path)메소드 의 버전 만 제공합니다 .
AlexMelw

52

EF Core : "ThenInclude"를 사용하여 여러 레벨로드 : 예 :

var blogs = context.Blogs
    .Include(blog => blog.Posts)
        .ThenInclude(post => post.Author)
        .ThenInclude(author => author.Photo)
    .ToList();

53
이것은 EF 코어 인 것 같습니다
Chris Marisic

27
참고 : VS2017은 인텔리 센스가 작동하지 않았습니다. 생각해야 할 방식으로 입력하면 오류 강조 표시가 사라집니다.
JohnWrensby

4
@JohnWrensby의 의견을 강조하고 싶습니다 .Intellisense는 때때로 이러한 ThenInclude를 처리하는 데 특히 오래 걸릴 수 있습니다. 이는 새로운 사용자에게는 혼란 스러울 수 있습니다. VS에 표시된 "오류"를 무시하고 입력하고 컴파일하기 전까지 간단한 람다 식 포함이 제대로 처리되지 않은 경우도있었습니다.
Pac0

@ Pac0 당신은 내 하루를 저장했습니다. 자식 항목을 보려고 고군분투했습니다.
Bendram

28

하위 엔터티를 좋은 방식으로 포함시키기 위해 Entity Framework 6 (.Net Core 스타일)에 대한 작은 도우미를 만들었습니다.

NuGet에 있습니다 : Install-Package ThenInclude.EF6

using System.Data.Entity;

var thenInclude = context.One.Include(x => x.Twoes)
    .ThenInclude(x=> x.Threes)
    .ThenInclude(x=> x.Fours)
    .ThenInclude(x=> x.Fives)
    .ThenInclude(x => x.Sixes)
    .Include(x=> x.Other)
    .ToList();

패키지는 GitHub에서 사용할 수 있습니다 .


안녕하세요, 런타임시 예외가 발생하여 IncludableQueryable <observablecollection>을 IncludableQueryable <genericcollection>으로 캐스트 할 수 없습니다
user2475096

나는 db를 먼저 사용하고 있으며 모든 엔티티에 대해 ObservableCollections를 가져 오기 위해 tt 파일을 수정했습니다. 도움을 환영합니다.
user2475096

2
@ lenny32이 확장과 관련하여 알아야 할 것이 있습니까?
Aaron Hudon

탐색하는 속성이 탐색 한 DbSet과 일대일이고 DbSet<One>().Include(x => x.Two.Three.Four.Five.Six), 직교 곱을 계산하고 잠재적으로 대역폭을 늘리는 유일한 결점으로 연결할 수있는 경우에는 필요하지 않습니다 .
John Zabroski

23

MSDN에 대한 더 많은 EFCore 예제Includeand를 사용 하여 매우 복잡한 작업을 수행 할 수 있음을 보여줍니다 ThenInclude.

이것은 얼마나 복잡한 지에 대한 좋은 예입니다 (이것은 모두 하나의 진술입니다!) :

viewModel.Instructors = await _context.Instructors

      .Include(i => i.OfficeAssignment)

      .Include(i => i.CourseAssignments)
        .ThenInclude(i => i.Course)
            .ThenInclude(i => i.Enrollments)
                .ThenInclude(i => i.Student)

      .Include(i => i.CourseAssignments)
        .ThenInclude(i => i.Course)
            .ThenInclude(i => i.Department)

      .AsNoTracking()
      .OrderBy(i => i.LastName)
      .ToListAsync();

Include이후에도 체인을 연결하는 방법 ThenInclude과 최상위 엔티티 (강사)의 수준으로 다시 '재설정'하는 방법을 확인하십시오.

동일한 '첫 번째 수준'컬렉션 (CourseAssignments)을 여러 번 반복 한 다음 별도의 ThenIncludes명령을 사용하여 다른 자식 엔터티를 얻을 수도 있습니다.

실제 검색어는 Include또는 ThenIncludes체인 끝에 태그되어야합니다 . 다음은 작동하지 않습니다.

var query = _context.Instructors.AsQueryable();
query.Include(i => i.OfficeAssignment);

var first10Instructors = query.Take(10).ToArray();

로깅을 설정하고 하나 또는 두 개 이상의 항목을 포함하는 경우 쿼리가 제어되지 않는지 확인하는 것이 좋습니다. 실제로 어떻게 작동하는지 확인하는 것이 중요합니다. 각각의 개별 '포함'은 중복 데이터를 반환하는 대규모 조인을 피하기 위해 일반적으로 새로운 쿼리입니다.

AsNoTracking 실제로 엔티티를 편집하고 다시 저장하지 않으려는 경우 작업 속도를 크게 높일 수 있습니다.


반복하지 않고 등록부와 부서를 모두 얻을 수있는 방법이 있습니까? CourseAssignment 및 Course를 포함합니까? (지금까지,이 API가 .ThenInclude으로 더 깊게, 또는 .Include와 최상위 다시,하지만 같은 수준의 숙박에 아무것도 할 것 같아?)
윌리엄 Jockusch

지연 로딩을 원한다면 EF Core 2.1 blogs.msdn.microsoft.com/dotnet/2018/02/02/…에 대해 계속 지켜봐 주시기 바랍니다. 그러나 같은 레벨에서 더 많은 것을로드하고 싶다면 이것이 의도적이라고 생각합니다. 나는 당신이 무엇을 생각하는지 잘 모르겠습니다.이 작업을 수행하는 데 많은 추가 작업이 필요하지 않으며 데이터베이스에서 다시 오는 것을 크게 줄입니다. 엔티티는 하나 또는 두 개의 '동일한 레벨'항목을 가질 수 있지만 대규모 프로젝트의 경우 50을 가질 수 있으며 명시 적 인 경우 앱이 훨씬 빠릅니다.
Simon_Weaver

이것은 레벨을 다시 초기 레벨로 "재설정"하는 개념에 대한 좋은 설명이었습니다. 내 성향 계급의 계층에 머리를 감쌀 수있었습니다. 건배!
AFM-Horizon

22

또한 여러 포함을 사용해야했고 3 단계에서 여러 속성이 필요했습니다.

(from e in context.JobCategorySet
                      where e.Id == id &&
                            e.AgencyId == agencyId
                      select e)
                      .Include(x => x.JobCategorySkillDetails)
                      .Include(x => x.Shifts.Select(r => r.Rate).Select(rt => rt.DurationType))
                      .Include(x => x.Shifts.Select(r => r.Rate).Select(rt => rt.RuleType))
                      .Include(x => x.Shifts.Select(r => r.Rate).Select(rt => rt.RateType))
                      .FirstOrDefaultAsync();

이것은 누군가를 도울 수 있습니다 :)


1
반복하지 .Include(x => x.Shifts.Select(r => r.Rate).Select(rt => rt......
않고이

글쎄, 그것은 당신이 가고 싶어 얼마나 깊은
dnxit

7

문자열 리터럴을 사용하는 것이 마음에 들지 않으면 해당 관계의 다중성에 관계없이 문자열 오버로드를 사용하여 중첩 레벨을 포함시킬 수 있음을 분명히 밝힙니다.

query.Include("Collection.Property")

1
이 방법은 몇 시간 동안 인터넷 검색을 한 후에도 찾을 수 없으므로 VB에서 어떻게 코딩 할 수 있는지 알아내는 데 도움이되었습니다.
코더

이것은 나를 위해 잘 작동합니다, 나는 이것을 많이 사용합니다! SelectMany 문과 결합하여 작동합니다.query.SelectMany(x=>x.foos).Include("bar").Include("bar.docs")...
Ephie
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.