단일 결합의 여러 필드에서 LINQ의 결합을 수행하는 방법


244

두 개 이상의 필드에서 조인을 수행하는 LINQ2DataSet 쿼리를 수행해야합니다.

var result = from x in entity
join y in entity2 
       on x.field1 = y.field1 
and 
          x.field2 = y.field2

아직 적절한 솔루션 (I는 where 절에 여분의 제약 조건을 추가 할 수 있지만이 적절한 해결책에서 멀리, 또는 사용 발견 솔루션을하지만은 동등 조인을 가정).

LINQ에서 단일 조인으로 여러 필드를 조인 할 수 있습니까?

편집하다

var result = from x in entity
             join y in entity2
             on new { x.field1, x.field2 } equals new { y.field1, y.field2 }

위의 equijoin을 가정하여 언급 한 솔루션입니다.

추가 편집

내 원래의 예가 동등 (equijoin)이라는 비판에 대답하기 위해, 나는 현재 요구 사항이 동등 (equijoin)에 대한 것이며 이미 위에서 언급 한 솔루션을 사용했음을 인정합니다.

그러나 LINQ에 어떤 가능성과 모범 사례를 적용해야하는지 이해하려고 노력하고 있습니다. 곧 테이블 ID로 날짜 범위 쿼리 조인을 수행해야하며 해당 문제를 선점했습니다 .where 절에 날짜 범위를 추가 해야하는 것처럼 보입니다.

주어진 모든 제안과 의견에 대해 언제나 감사합니다.


48
이 클래스를 읽는 사람에게는 참고로, 클래스 클래스에서 다중 필드 조인을 수행하는 경우 두 클래스 클래스의 필드 이름을 동일하게 지정해야합니다. 그렇지 않으면 컴파일 오류가 발생합니다.
Mark

6
또는 이름이 일치하는지 확인해야합니다. 즉, 다른 anon 유형 중 하나의 필드 이름만으로 다른 유형과 일치시킬 수 있습니다.
Tom Ferguson

1
이 답변에주의를 기울이십시오 stackoverflow.com/a/34176502/1704458
TS

나는 객체가 아니라 등호의 양쪽에 튜플을 사용했으며 작동하는 것처럼 보였습니다.
GHZ

답변:


89

익명 유형의 솔루션이 제대로 작동합니다. LINQ (조인 절을 사용하여) equijoin 만 나타낼 있으며 실제로는 원래 쿼리를 기반으로 표현하고 싶다고 말한 것입니다.

특정 이유로 익명 유형의 버전이 마음에 들지 않으면 해당 이유를 설명해야합니다.

원래 요청한 것과 다른 것을 하고 싶다면 실제로 하고 싶은 일의 예를 들어주십시오 .

편집 : 질문의 편집에 응답 : 예, "날짜 범위"결합을 수행하려면 대신 where 절을 사용해야합니다. 그것들은 실제로 의미 적으로 동등하므로 사용 가능한 최적화의 문제 일뿐입니다. Equijoins는 내부 시퀀스를 기반으로 조회를 생성하여 간단한 최적화 (LINQ to Objects, LINQ to DataSet 포함)를 제공합니다. 키에서 해당 키와 일치하는 항목 시퀀스까지의 해시 테이블로 생각하십시오.

날짜 범위로 처리하는 것이 다소 어렵습니다. 그러나 "날짜 범위 조인"이 의미하는 바에 따라 비슷한 작업을 수행 할 수 있습니다. 날짜에 "밴드"를 생성하려는 경우 (예 : 연 1 회) 같은 연도 (동일한 날짜는 아님)가 일치해야하며, 해당 밴드를 키로 사용하면됩니다. 더 복잡한 경우, 예를 들어 조인의 한 쪽이 범위를 제공하고 조인의 다른 쪽이 단일 날짜를 제공하여 해당 범위 내에 있으면 일치하는 where조항으로 처리하는 것이 더 좋습니다 (1 초 후)from조항) IMO. 한 쪽 또는 다른 쪽을 주문하여보다 효율적으로 일치하는 항목을 찾으면 특히 펑키 한 마술을 할 수 있지만 많은 작업이 필요합니다. 성능이 문제인지 확인한 후에 만 ​​그런 일을 할 것입니다.


고맙습니다. 예, where 절을 사용하면 성능이 크게 걱정됩니다. 조인 후 where 절이 두 번째 조인 매개 변수를 도입하여 줄일 수있는 더 큰 데이터 세트에서 필터를 수행한다고 생각합니다. 효율성 향상을 얻을 수 있는지 테스트하라는 주문 아이디어를 좋아합니다
johnc

몇 개의 기록을 가지고 있습니까? 결과를 시작하는 데 시작하는 데 일정 시간이 걸린다는 것을 잊지 마십시오.
Jon Skeet

"그들은 실제로 의미 상 동등하다"-거기에 '정말'이라는 단어가 필요한가? 아마도 당신은 "그들은있어, 의미가 정말 :) 동일한 의미를"
onedaywhen

136
var result = from x in entity
   join y in entity2 on new { x.field1, x.field2 } equals new { y.field1, y.field2 }

이것은 101 Linq Samples가 이것을 보지 못했거나 내가 보지 못했을 때보 고 싶었습니다.
Chris Marisic

1
@PeterX 실제로는, 여기 내 대답을 볼 수 stackoverflow.com/a/22176658/595157
niieani

13
위의 코드는 작동하지 않았습니다. 추가 한 후에 on new { X1= x.field1, X2= x.field2 } equals new { X1=y.field1, X2= y.field2 } 작동
Ravi Ram

@ Ravi Ram .. 감사합니다 .. 귀하의 의견이 도움이되었습니다
NMathur

80
var result = from x in entity1
             join y in entity2
             on new { X1= x.field1, X2= x.field2 } equals new { X1=y.field1, X2= y.field2 }

두 엔티티에서 열 이름이 다른 경우이를 수행해야합니다.


6
다른 열 이름을 언급 해 주셔서 감사합니다. 이것은 나의 나쁜 표현을 고쳤다.
Gaʀʀʏ

1
이것은 나에게도 효과가있었습니다. 열 이름이 일치하지 않으면 "조인 절의 식 중 하나의 형식이 잘못되었습니다. 'GroupJoin'을 호출 할 때 형식 유추에 실패했습니다."라는 오류가 발생합니다.
humbads

주요 변수의 별칭을 지정해 주셔서 감사합니다.
Thomas. 벤츠

int의 모든 속성 이름을 'new {}'로 지정하지 않았을 때 @humbads가 언급 한 오류가 발생했습니다. 따라서 이름을 지정하면 나머지 이름도 지정해야합니다.
Ethan Melamed

감사합니다
Charly H

51

동등한 메소드 체인 구문으로이를 완료하십시오.

entity.Join(entity2, x => new {x.Field1, x.Field2},
                     y => new {y.Field1, y.Field2}, (x, y) => x);

마지막 인수 (x, y) => x는 당신이 선택 하는 반면 (위의 경우 우리는을 선택합니다 x).


31

더 읽기 쉽고 유연한 옵션은 Where 함수를 사용하는 것입니다.

var result = from x in entity1
             from y in entity2
                 .Where(y => y.field1 == x.field1 && y.field2 == x.field2)

또한 .DefaultIfEmpty ()를 추가하여 내부 조인에서 왼쪽 조인으로 쉽게 변경할 수 있습니다.


오랜 시간 동안 람다 사용자로서 (질문을 할 때와는 달리), 나는 동의해야 할 것입니다.
johnc

이것이 느려질까요?
AlfredBr

1
새로운 { ... } equals new { ... }구문 과 동일한 성능을 가져야한다고 생각 합니다. LinqPad 는 표현식이 어떻게 동작하는지 확인할 수있는 훌륭한 도구입니다 (LINQ2SQL을 사용하는 경우 SQL 스크립트, 표현식 트리 등)
Alexei

내가 INNER JOIN 대신에 CROSS JOIN을 생산하는 것을 알았을 때
Mariusz

@Mariusz 예, INNER JOIN 대신 CROSS JOIN + WHERE를 생성하는 것이 좋습니다. 간단한 쿼리의 경우 분석기가 매우 유사한 것을 생성 할 것으로 기대합니다.
Alexei

10
var result = from x in entity
             join y in entity2
             on new { X1= x.field1, X2= x.field2 } equals new { X1=y.field1, X2= y.field2 }
             select new 
             {
               /// Columns
              };

8

당신은 (아래)와 같은 것을 할 수 있습니다

var query = from p in context.T1

        join q in context.T2

        on

        new { p.Col1, p.Col2 }

        equals

         new { q.Col1, q.Col2 }

        select new {p...., q......};

내가 언급했듯이, 그것은 equijoin이 필요합니다
johnc

7

조인 연산자를 사용하면 동등 조인 만 수행 할 수 있습니다. 다른 연산자를 사용하여 다른 유형의 조인을 구성 할 수 있습니다. 이 방법을 사용하거나 where 절을 변경하여 정확한 조인이 더 쉬운 지 확실하지 않습니다. join 절에 대한 문서는 여기 에서 찾을 수 있습니다 . MSDN에는 다른 조인의 예에 대한 여러 개의 링크 가있는 조인 작업에 대한 기사 도 있습니다.


3

엔터티에서 필드 이름이 다른 경우

var result = from x in entity
   join y in entity2 on 
          new {
                field1=   x.field1,
               field2 =  x.field2 
             } 
          equals
         new { 
                field1= y.field1,
                field2=  y.myfield
              }
select new {x,y});

감사합니다. 이름이 일치하지 않는 부분이 있습니다.
Brett

2

다음과 같은 전체 메소드 체인으로 :

lista.SelectMany(a => listb.Where(xi => b.Id == a.Id && b.Total != a.Total),
                (a, b) => new ResultItem
                {
                    Id = a.Id,
                    ATotal = a.Total,
                    BTotal = b.Total
                }).ToList();

-2
from d in db.CourseDispatches
                             join du in db.DispatchUsers on d.id equals du.dispatch_id
                             join u in db.Users on du.user_id equals u.id
                             join fr in db.Forumreports on (d.course_id + '_' + du.user_id)  equals  (fr.course_id + '_'+ fr.uid)

이것은 나를 위해 작동


이것은 다수의 가입을 위해, 그는이 하나의 여러 필드에 가입하고 싶어입니다 가입
theLaw

-3

결합하려는 요소를 보유 할 클래스 (Type)를 선언하십시오. 아래 예제에서 JoinElement 를 선언 하십시오.

 public class **JoinElement**
{
    public int? Id { get; set; }
    public string Name { get; set; }

}

results = from course in courseQueryable.AsQueryable()
                  join agency in agencyQueryable.AsQueryable()
                   on new **JoinElement**() { Id = course.CourseAgencyId, Name = course.CourseDeveloper } 
                   equals new **JoinElement**() { Id = agency.CourseAgencyId, Name = "D" } into temp1

1
이것은 이미 9 년 전에 답변되었습니다 ...이 답변은 어떤 가치를 가져 옵니까?
Maciej Jureczko
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.