Linq to Entities 가입 및 그룹 가입


182

웹을 검색했지만 여전히 간단한 답변을 찾을 수 없습니다. 누군가 간단한 영어로 설명해 주 GroupJoin시겠습니까? 일반 내부와 Join어떻게 다릅니 까? 일반적으로 사용됩니까? 메소드 구문에만 해당됩니까? 쿼리 구문은 어떻습니까? C # 코드 예제가 좋을 것입니다.


MSDN에 따르면 그룹 조인은 into 표현식의 조인 절입니다. join 절 에는 자세한 정보와 코드 샘플이 있습니다. 본질적으로 내부 조인입니다 (오른쪽의 요소가 왼쪽의 요소와 일치하지 않으면 null 결과가 나타남). 그러나 결과는 그룹으로 구성됩니다.
Tim

답변:


375

행동

두 개의 목록이 있다고 가정하십시오.

Id  Value
1   A
2   B
3   C

Id  ChildValue
1   a1
1   a2
1   a3
2   b1
2   b2

때 당신에게 Join온 두 목록 Id결과가 될 것입니다 필드 :

Value ChildValue
A     a1
A     a2
A     a3
B     b1
B     b2

때 당신에게 GroupJoin온 두 목록 Id결과가 될 것입니다 필드 :

Value  ChildValues
A      [a1, a2, a3]
B      [b1, b2]
C      []

따라서 Join부모 및 자식 값의 플랫 (표) 결과가 생성됩니다.
GroupJoin첫 번째 목록에 항목 목록을 생성하며, 각 목록은 두 번째 목록에 결합 된 항목 그룹이 있습니다.

이것이 SQL Join에서와 같은 이유 입니다 .에 INNER JOIN대한 항목이 없습니다 C. 하지만 GroupJoin상당의이 OUTER JOIN: C결과 집합에 있지만 관련 항목의 목록이 비어 (AN SQL 결과의 행이있을 것입니다 설정 C - null).

통사론

따라서 두 목록 IEnumerable<Parent>IEnumerable<Child>각각 시키십시오 . (Linq-엔티티의 경우 :) IQueryable<T>.

Join 문법은

from p in Parent
join c in Child on p.Id equals c.Id
select new { p.Value, c.ChildValue }

반환 IEnumerable<X>여기서 X는 두 가지 특성을 가진 익명의 유형, ValueChildValue. 이 쿼리 구문은 Join후드 아래의 메서드를 사용합니다 .

GroupJoin 문법은

from p in Parent
join c in Child on p.Id equals c.Id into g
select new { Parent = p, Children = g }

복귀하면 IEnumerable<Y>Y는 한 종류의 속성으로 구성된 익명 형식이다 Parent및 유형의 속성 IEnumerable<Child>. 이 쿼리 구문은 GroupJoin후드 아래의 메서드를 사용합니다 .

우리 select g는 후자의 쿼리에서 할 수 있습니다 IEnumerable<IEnumerable<Child>>.리스트를 선택하십시오 . 많은 경우 부모가 포함 된 선택이 더 유용합니다.

일부 사용 사례

1. 편평한 외부 결합 생성.

말했듯이, 진술 ...

from p in Parent
join c in Child on p.Id equals c.Id into g
select new { Parent = p, Children = g }

... 하위 그룹이있는 부모 목록을 생성합니다. 이것은 두 가지 작은 추가로 부모-자식 쌍의 간단한 목록으로 전환 될 수 있습니다.

from p in parents
join c in children on p.Id equals c.Id into g // <= into
from c in g.DefaultIfEmpty()               // <= flattens the groups
select new { Parent = p.Value, Child = c?.ChildValue }

결과는

Value Child
A     a1
A     a2
A     a3
B     b1
B     b2
C     (null)

합니다 범위 변수가 c 위의 문에서 재사용된다. 이렇게하면 기존 명세서에 해당하는 것을 추가하여 모든 join명세서를 간단히로 변환 할 수 있습니다 .outer joininto g from c in g.DefaultIfEmpty()join

여기에서 쿼리 (또는 포괄적) 구문이 빛을 발합니다. 메소드 (또는 유창한) 구문은 실제로 일어나는 일을 보여 주지만 쓰기는 어렵습니다.

parents.GroupJoin(children, p => p.Id, c => c.Id, (p, c) => new { p, c })
       .SelectMany(x => x.c.DefaultIfEmpty(), (x,c) => new { x.p.Value, c?.ChildValue } )

따라서 outer joinLINQ 의 플랫 은로 GroupJoin병합됩니다 SelectMany.

2. 주문 보존

부모 목록이 조금 더 길다고 가정하십시오. 일부 UI는 선택된 부모 목록을 Id고정 된 순서대로 값 으로 생성합니다 . 사용합시다 :

var ids = new[] { 3,7,2,4 };

이제 선택한 부모를 부모 목록에서이 순서대로 필터링해야합니다.

우리가한다면 ...

var result = parents.Where(p => ids.Contains(p.Id));

...의 순서에 parents따라 결과가 결정됩니다. 부모가을 (를) 주문 Id하면 결과는 부모 2, 3, 4, 7입니다. 좋지 않습니다. 그러나 join목록을 필터링하는 데 사용할 수도 있습니다 . 그리고 ids첫 번째 목록 으로 사용 하면 순서가 유지됩니다.

from id in ids
join p in parents on id equals p.Id
select p

결과는 부모 3, 7, 2, 4입니다.


따라서 GroupJoin에서 하위 값에는 관련 값이 포함 된 개체가 포함됩니까?
duyn9uyen

당신이 말했듯이 GroupJoin은 외부 조인과 같지만 구문 (그룹 조인의 linq)은 외부 조인과 같지 않지만 왼쪽 외부 조인과 같습니다.
Imad

2
"플랫 외부 조인"을 왼쪽 외부 조인으로 지정한다고 생각합니다.
NetMage

1
완벽하게, 지금은 이해 설명
peterincumbria

19

eduLINQ 에 따르면 :

GroupJoin이하는 일을 파악하는 가장 좋은 방법은 Join을 생각하는 것입니다. 전체적인 아이디어는 "외부"입력 시퀀스를 살펴보고 "내부"시퀀스에서 모든 일치하는 항목을 찾은 다음 (각 시퀀스의 주요 투영을 기반으로) 일치하는 요소 쌍을 산출하는 것이 었습니다. GroupJoin은 요소 쌍을 생성하는 대신 해당 항목과 일치하는 "내부"항목을 기반으로 각 "외부"항목에 대해 단일 결과를 생성한다는 점을 제외하고 비슷합니다 .

유일한 차이점은 return 문입니다.

가입 :

var lookup = inner.ToLookup(innerKeySelector, comparer); 
foreach (var outerElement in outer) 
{ 
    var key = outerKeySelector(outerElement); 
    foreach (var innerElement in lookup[key]) 
    { 
        yield return resultSelector(outerElement, innerElement); 
    } 
} 

그룹 조인 :

var lookup = inner.ToLookup(innerKeySelector, comparer); 
foreach (var outerElement in outer) 
{ 
    var key = outerKeySelector(outerElement); 
    yield return resultSelector(outerElement, lookup[key]); 
} 

여기에서 더 읽으십시오 :

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