2017-03-09 4 views
0

여러 포함을 포함하는 linq 쿼리를 단순화하고 싶습니다.여러 포함을 포함하는 Linq 요청을 어떻게 나누는가?

내 모델은 간단합니다. 사이트는 하나의 계약서에 링크되어 있으며, 이는 하나의 클라이언트에 연결되어 있습니다. 그 고객은 전화, 우편 및 honorifics (appelRef) 하나의 요청을 받아야합니다.

요청 뒤에 있기 때문에 엔티티 프레임 워크에서 SQL Server 요청으로 변환되므로 단일 요청이 필요합니다.

var search = 
from IMT.Site s in imtContext.IMTObjects.OfType<IMT.Site>() 
.Include(
s => s.LienContratSiteRef 
    .Select(l => l.Contrat) 
     .Select(c => c.LienContratClientRef 
      .Select(l => l.Client) 
       .Select(cl => cl.Telephones))) 

.Include(s => s.LienContratSiteRef 
    .Select(l => l.Contrat) 
     .Select(c => c.LienContratClientRef 
      .Select(l => l.Client) 
       .Select(cl => cl.Mails))) 

.Include(s => s.LienContratSiteRef 
    .Select(l => l.Contrat) 
     .Select(c => c.LienContratClientRef 
      .Select(l => l.Client) 
       .Select(cl => cl.AppelRef))) 

where s.Reference.ToString() == siteId 
select s; 

YOR가

.Include(
s => s.LienContratSiteRef 
    .Select(l => l.Contrat) 
     .Select(c => c.LienContratClientRef 
      .Select(l => l.Client) 

..is 세 번 반복 된 블록을 알 수있다 : 여기

는 LINQ 요청이다. 코드 블록을 인수 분해하는 방법이 있습니까?

업데이트 : Intermedray 개체 LienContratSiteRef 및 LienContratClientRef가 있고 관계가 0 - *이므로 LienContratSiteRef.Contrat 및 LienContratClientRef.Client는 컬렉션입니다.

.Include(
s => s.LienContratSiteRef 
    .Select(l => l.Contrat) 
     .Select(c => c.LienContratClientRef 
      .Select(l => l.Client) 
       .Select(cl => new { Tels = cl.Telephones, Mail = cl.Mails, Appel = cl.AppelRef}))) 

을하지만 그것은 런타임 오류 발생 :

나는 또한 시도

The Include path expression must refer to a navigation property defined on the type.

+0

당신은 그렇게 할 수 있지만,이 코드는 나중에 유사한 경우에 재사용 될 수 있지만 (아주 일부 코드가 발생할 수있는 수동 표현을 포함 구축이 필요합니다 :이 메모리에 쿼리를 실행 한 후 나는 생각한다). – Evk

답변

0

문자열 기반

완료를 뽑아 사용할 수있는 Include() method supports a dot-delimited string parameter 체인으로 연결 여러 체인 연결된 선택 호출을 만드는 것과 반대되는 개체 그래프 :

여러 추가 속성을 포함하기를 원한다면 거기에서
.Include("LienContratSiteRif.Contrat.LienContratClientRef.Client") 

은, 당신이 다른 그 하위 속성을 포함 할 수 있다고 생각 :

.Include("LienContratSiteRif.Contrat.LienContratClientRef.Client, Client.Telephones, ...") 

람다 기반

가 체인으로 연결

당신이해야 람다 기반의 인클루드를 단일 Include() 콜에 연결하여 비슷한 것을 달성 할 수 있어야합니다 :

.Include(c => LienContratSiteRif.Contrat.LienContratClientRef.Client)

+0

해당 구문으로 작동합니다 : .Include ("LienContratSiteRef.Contrat.LienContratClientRef.Client.Telephones"). 포함 ("LienContratSiteRef.Contrat.LienContratClientRef.Client.Mails"). 포함 ("LienContratSiteRef.Contrat.LienContratClientRef.Client .AppelRef ") 모델 변경시 단점은 컴파일 타임 오류가 아닙니다. 두 번째 형식 인 Client.Mails, Client.AppelRef가 작동하지 않습니다. 콘텐트에는 LienContratSiteRef 및 LienContratClientRef에 대한 탐색 속성이 없으므로 마지막 양식을 사용할 수 없습니다. – abreneliere

0

포함 내에있는 s => ...은 대리인으로 리팩토링 될 수 있으며, 그 다음에 여러 번 위임되는 .Include입니다.

서명이 Func<Site, IEnumerable<Client>> 인 것처럼 보입니까?

예.

static IEnumerable<Client> Foo(Site site) => site.LienContratSiteRef 
    .Select(l => l.Contrat) 
     .Select(c => c.LienContratClientRef 
      .Select(l => l.Client) 
0

엔티티 프레임 워크 프로젝션을 만드는 것처럼 보입니다.

프로젝트를 사용하면 반환 할 속성 만 선택할 수 있습니다.

는 프로젝션을 사용하려면 (단지 SQL 선택처럼), 코드는 대략 다음과 같아야합니다

var search = imtContext.IMTObjects.OfType<IMT.Site>() 
.Where(s => s.Reference.ToString() == siteId) 
.Select(s => new { 
    Telephones = s.LienContratSiteRef.Contrat.Select(c => c.LienContratClientRef.Client.Select(cli => cli.Telephones), 
    Mails = s.LienContratSiteRef.Contrat.Select(c => c.LienContratClientRef.Client.Select(cli => cli.Mails), 
    AppelRef = s.LienContratSiteRef.Contrat.Select(c => c.LienContratClientRef.Client.Select(cli => cli.AppelRef)  
}).ToList(); 

Mails, Telephones 경우, AppelRef는 당신이 함께 같은 컬렉션을 집계 할 수있는, 또한 모음입니다

var telephones = search.SelectMany(x => x.Telephones).ToList(); 
var mails = search.SelectMany(x => x.Mails).ToList(); 
var appelRefs = search.SelectMany(x => x.AppelRef).ToList(); 
+0

LienContratSiteRef.Contrat와 LienContratClientRef.Client는 콜렉션이기 때문에 s.LienContratSiteRef.Contrat.LienContratClientRef.Client.Telephones 구문을 사용할 수 없습니다 (방금 정밀도를 추가하는 질문이 업데이트되었습니다). – abreneliere

+0

아! 그에 따라 답변을 업데이트하겠습니다. – Ermish