LINQ에서 왼쪽 외부 가입


538

join-on-equals-into절 을 사용하지 않고 C # LINQ에서 개체에 대해 왼쪽 외부 조인을 수행하는 방법은 무엇입니까? where절로 그렇게 할 수있는 방법이 있습니까? 올바른 문제 : 내부 조인이 쉽고 이런 해결책이 있습니다.

List<JoinPair> innerFinal = (from l in lefts from r in rights where l.Key == r.Key
                             select new JoinPair { LeftId = l.Id, RightId = r.Id})

그러나 왼쪽 외부 조인에는 솔루션이 필요합니다. 광산은 이런 식이지만 작동하지 않습니다.

List< JoinPair> leftFinal = (from l in lefts from r in rights
                             select new JoinPair { 
                                            LeftId = l.Id, 
                                            RightId = ((l.Key==r.Key) ? r.Id : 0
                                        })

여기서 JoinPair는 클래스입니다.

public class JoinPair { long leftId; long rightId; }

2
당신이 달성하려는 것을 예를 들어 줄 수 있습니까?
jeroenh

일반적인 왼쪽 외부 조인은 다음과 같습니다. var a = from b b in bb join c의 cc에서 b.bbbbb는 c.ccccc와 dd의 d에서 dd.DefaultIfEmpty ()의 select b.sss; 내 질문은 다음과 같은 join-on-equals-into 절을 사용하여 그 witouth를 수행 할 수있는 방법이 있습니다. .
장난감

1
사람들이 더 나은 답변을 줄 수 있도록 이미 가지고있는 코드의 예를 게시해야합니다.
Sloth

나는 "왼쪽 제외 "조인 을 찾고 있었다 (그리고 나는 "OUTER"의 개념과 혼동했다). 이 답변은 내가 원하는 것에 더 가깝습니다.
The Red Pea

답변:


598

에 명시된 바와 같이 :

LINQ 샘플 101 개-왼쪽 외부 결합

var q =
    from c in categories
    join p in products on c.Category equals p.Category into ps
    from p in ps.DefaultIfEmpty()
    select new { Category = c, ProductName = p == null ? "(No products)" : p.ProductName };

7
같은 일을 시도하고 있지만 조인 연산자에서 오류가 발생합니다. "조인 절에있는 표현식 중 하나의 유형이 잘못되었습니다."
Badhon Jain

3
@jain 유형이 다르면 조인이 작동하지 않습니다. 따라서 키의 데이터 유형이 다를 수 있습니다. 예를 들어 두 키가 모두 맞습니까?
Yooakim

2
해결책 Jain은 무엇입니까? 나는 또한 같은 오류에 직면하고 있으며 제 경우에도 유형이 동일합니다.
Sandeep

1
@Sandeep 당신이 가입 한 키를 확인하십시오. 그것들이 string과 int 타입이라면 string 키를 int로 변환하십시오.
Ankit


546

데이터베이스 기반 LINQ 공급자를 사용하면 다음과 같이 훨씬 더 읽기 쉬운 왼쪽 외부 조인을 작성할 수 있습니다.

from maintable in Repo.T_Whatever 
from xxx in Repo.T_ANY_TABLE.Where(join condition).DefaultIfEmpty()

당신이 생략하면 DefaultIfEmpty() 내부 조인이됩니다.

수락 된 답변을 선택하십시오.

  from c in categories
    join p in products on c equals p.Category into ps
    from p in ps.DefaultIfEmpty()

이 구문은 매우 혼란스럽고 MULTIPLE 테이블을 조인하려는 경우 어떻게 작동하는지 명확하지 않습니다.

참고 행당을 도입하지 않는 한 (적절한) 데이터베이스 최적화 프로그램이 왼쪽 조인으로 완벽하게 변환 할 수있는 외부 적용 / 왼쪽 결합 측면과 동일
하다는 점에 유의해야합니다. from alias in Repo.whatever.Where(condition).DefaultIfEmpty()-값 (실제 외부 적용). Linq-Object를 사용하는 경우 DB 최적화 프로그램이 없기 때문에 Linq-2-Objects에서이 작업을 수행하지 마십시오.

자세한 예

var query2 = (
    from users in Repo.T_User
    from mappings in Repo.T_User_Group
         .Where(mapping => mapping.USRGRP_USR == users.USR_ID)
         .DefaultIfEmpty() // <== makes join left join
    from groups in Repo.T_Group
         .Where(gruppe => gruppe.GRP_ID == mappings.USRGRP_GRP)
         .DefaultIfEmpty() // <== makes join left join

    // where users.USR_Name.Contains(keyword)
    // || mappings.USRGRP_USR.Equals(666)  
    // || mappings.USRGRP_USR == 666 
    // || groups.Name.Contains(keyword)

    select new
    {
         UserId = users.USR_ID
        ,UserName = users.USR_User
        ,UserGroupId = groups.ID
        ,GroupName = groups.Name
    }

);


var xy = (query2).ToList();

LINQ 2 SQL과 함께 사용하면 다음과 같은 매우 읽기 쉬운 SQL 쿼리로 변환됩니다.

SELECT 
     users.USR_ID AS UserId 
    ,users.USR_User AS UserName 
    ,groups.ID AS UserGroupId 
    ,groups.Name AS GroupName 
FROM T_User AS users

LEFT JOIN T_User_Group AS mappings
   ON mappings.USRGRP_USR = users.USR_ID

LEFT JOIN T_Group AS groups
    ON groups.GRP_ID == mappings.USRGRP_GRP

편집하다:

보다 복잡한 예 는 " SQL Server 쿼리를 Linq 쿼리로 변환 "을 참조하십시오 .

또한 Linq-2-SQL 대신 Linq-2-Objects에서 수행하는 경우 LINQ to SQL이 작업을 조인하기 위해 올바르게 변환하기 때문에이 방법을 객체로 사용하기 때문에 구식 방식으로 수행해야합니다. 전체 검색을 강제 실행하고 색인 검색을 이용하지 않습니다.

    var query2 = (
    from users in Repo.T_Benutzer
    join mappings in Repo.T_Benutzer_Benutzergruppen on mappings.BEBG_BE equals users.BE_ID into tmpMapp
    join groups in Repo.T_Benutzergruppen on groups.ID equals mappings.BEBG_BG into tmpGroups
    from mappings in tmpMapp.DefaultIfEmpty()
    from groups in tmpGroups.DefaultIfEmpty()
    select new
    {
         UserId = users.BE_ID
        ,UserName = users.BE_User
        ,UserGroupId = mappings.BEBG_BG
        ,GroupName = groups.Name
    }

);

21
이 답변은 실제로 도움이됩니다. 실제로 이해할 수있는 구문을 제공해 주셔서 감사합니다.
Chris Marisic

3
WTB NHibernate에 호환 LINQ 쿼리 ... :)
mxmissile

30
LINQ to SQL은이를 조인 작업으로 올바르게 변환합니다. 그러나 객체보다이 방법을 사용하면 전체 스캔이 수행됩니다. 공식 문서에서 해시를 사용하여 인덱스 검색을 수행 할 수있는 그룹 조인 솔루션을 제공합니다.
타 미르 다니엘 리

3
명시 적 구문은 그 다음에 joinwhereDefaultIfEmpty
나오는

1
@ user3441905 : 테이블 a를 테이블 b와 조인 해야하는 한 이것이 될 수 있습니다. 그러나 그 이상을 얻으면 그렇지 않을 것입니다. 그러나 2 테이블조차도 지나치게 부자유하다고 생각합니다. 이 답변은 최상위 답변에 이미 90 개 이상의 공감대가 있었을 때 0으로 시작되었으므로 인기있는 의견은 귀하에게 반대되는 것 같습니다.
Stefan Steiger

131

람다 식 사용

db.Categories    
  .GroupJoin(db.Products,
      Category => Category.CategoryId,
      Product => Product.CategoryId,
      (x, y) => new { Category = x, Products = y })
  .SelectMany(
      xy => xy.Products.DefaultIfEmpty(),
      (x, y) => new { Category = x.Category, Product = y })
  .Select(s => new
  {
      CategoryName = s.Category.Name,     
      ProductName = s.Product.Name   
  });

8
Join과 GroupJoin은 실제로 왼쪽 조인을 지원하지 않습니다. GroupJoin을 사용하는 요령은 빈 그룹을 가지고 빈 그룹을 빈 값으로 변환하는 것입니다. DefaultIfEmpty는 간단히 그렇게합니다. 즉 Enumerable.Empty<Product>.DefaultIfEmpty(), 단일 값으로 IEnumerable을 반환합니다 default(Product).
타 미르 다니엘 리

61
이 모든 왼쪽 조인을 수행하려면 ??
FindOut_Quran

7
감사합니다! 람다 표현 예제가 너무 많지 않아서 이것이 효과가있었습니다.
Johan Henkens

1
답변 해주셔서 감사합니다. 몇 년 동안 쓴 원시 SQL LEFT OUTER JOIN에 가장 가까운 결과를 얻었습니다.
John Gathogo

1
마지막 Select ()가 실제로 필요하지 않으므로 SelectMany ()의 anon obj는 동일한 출력에 대해 리팩터링 될 수 있습니다. 또 다른 생각은 더 가까운 LEFT JOIN 동등성을 시뮬레이션하기 위해 y를 null로 테스트하는 것입니다.
데니 야곱

46

이제 확장 방법으로 :

public static class LinqExt
{
    public static IEnumerable<TResult> LeftOuterJoin<TLeft, TRight, TKey, TResult>(this IEnumerable<TLeft> left, IEnumerable<TRight> right, Func<TLeft, TKey> leftKey, Func<TRight, TKey> rightKey,
        Func<TLeft, TRight, TResult> result)
    {
        return left.GroupJoin(right, leftKey, rightKey, (l, r) => new { l, r })
             .SelectMany(
                 o => o.r.DefaultIfEmpty(),
                 (l, r) => new { lft= l.l, rght = r })
             .Select(o => result.Invoke(o.lft, o.rght));
    }
}

일반적으로 join을 사용하는 것처럼 사용하십시오.

var contents = list.LeftOuterJoin(list2, 
             l => l.country, 
             r => r.name,
            (l, r) => new { count = l.Count(), l.country, l.reason, r.people })

이것이 시간을 절약하기를 바랍니다.


44

예제를 살펴보십시오 . 이 쿼리는 작동해야합니다.

var leftFinal = from left in lefts
                join right in rights on left equals right.Left into leftRights
                from leftRight in leftRights.DefaultIfEmpty()
                select new { LeftId = left.Id, RightId = left.Key==leftRight.Key ? leftRight.Id : 0 };

3
r조인을 사용한 후 select 절에서 액세스 할 수 있습니까 ?
Farhad Alizadeh Noori가

@FarhadAlizadehNoori 예 그렇습니다.
Po-ta-toe

저자는 아마도 r두 번째 from조항 에서 재사용을 의미했을 것입니다 . 즉, from r in lrs.DefaultIfEmpty()그렇지 않으면이 쿼리는 의미가 없으며 r선택에 대한 컨텍스트를 벗어 났기 때문에 컴파일되지 않을 수도 있습니다.
Saeb Amini

@ Devart, 귀하의 질문을 읽었을 때 ClockwiseJohn Cleese와 함께 영화 를 떠올리게했습니다 .
Matas Vaitkevicius

1
leftRights에서 왼쪽 권리에 leftrights로 우측으로 왼쪽에서 ... 아 이름 : Jeez ... LEFT OUTER를 사용하는 구문은 LINQ에 가입 정말 명확하지 않다, 그러나이 이름은 정말 더 명확합니다.
Mike Gledhill

19

확장 메소드에 의한 왼쪽 외부 조인의 구현은 다음과 같습니다.

public static IEnumerable<Result> LeftJoin<TOuter, TInner, TKey, Result>(
  this IEnumerable<TOuter> outer, IEnumerable<TInner> inner
  , Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector
  , Func<TOuter, TInner, Result> resultSelector, IEqualityComparer<TKey> comparer)
  {
    if (outer == null)
      throw new ArgumentException("outer");

    if (inner == null)
      throw new ArgumentException("inner");

    if (outerKeySelector == null)
      throw new ArgumentException("outerKeySelector");

    if (innerKeySelector == null)
      throw new ArgumentException("innerKeySelector");

    if (resultSelector == null)
      throw new ArgumentException("resultSelector");

    return LeftJoinImpl(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer ?? EqualityComparer<TKey>.Default);
  }

  static IEnumerable<Result> LeftJoinImpl<TOuter, TInner, TKey, Result>(
      IEnumerable<TOuter> outer, IEnumerable<TInner> inner
      , Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector
      , Func<TOuter, TInner, Result> resultSelector, IEqualityComparer<TKey> comparer)
  {
    var innerLookup = inner.ToLookup(innerKeySelector, comparer);

    foreach (var outerElment in outer)
    {
      var outerKey = outerKeySelector(outerElment);
      var innerElements = innerLookup[outerKey];

      if (innerElements.Any())
        foreach (var innerElement in innerElements)
          yield return resultSelector(outerElment, innerElement);
      else
        yield return resultSelector(outerElment, default(TInner));
     }
   }

그러면 결과 선택기가 널 요소를 처리해야합니다. Fx.

   static void Main(string[] args)
   {
     var inner = new[] { Tuple.Create(1, "1"), Tuple.Create(2, "2"), Tuple.Create(3, "3") };
     var outer = new[] { Tuple.Create(1, "11"), Tuple.Create(2, "22") };

     var res = outer.LeftJoin(inner, item => item.Item1, item => item.Item1, (it1, it2) =>
     new { Key = it1.Item1, V1 = it1.Item2, V2 = it2 != null ? it2.Item2 : default(string) });

     foreach (var item in res)
       Console.WriteLine(string.Format("{0}, {1}, {2}", item.Key, item.V1, item.V2));
   }

4
입니다 그러나 객체에 LINQ에 대한 옵션, 그리고이 작업의 가장 일반적인 사용 방법으로 어떤 쿼리 공급자에 대한 쿼리를 변환 할 수 없습니다.
Servy

13
그러나 문제는 "C # LINQ에서 개체 에 대한 왼쪽 외부 조인을 수행하는 방법 ..." 이었습니다.
Bertrand

12

이 예제를 보아라

class Person
{
    public int ID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Phone { get; set; }
}

class Pet
{
    public string Name { get; set; }
    public Person Owner { get; set; }
}

public static void LeftOuterJoinExample()
{
    Person magnus = new Person {ID = 1, FirstName = "Magnus", LastName = "Hedlund"};
    Person terry = new Person {ID = 2, FirstName = "Terry", LastName = "Adams"};
    Person charlotte = new Person {ID = 3, FirstName = "Charlotte", LastName = "Weiss"};
    Person arlene = new Person {ID = 4, FirstName = "Arlene", LastName = "Huff"};

    Pet barley = new Pet {Name = "Barley", Owner = terry};
    Pet boots = new Pet {Name = "Boots", Owner = terry};
    Pet whiskers = new Pet {Name = "Whiskers", Owner = charlotte};
    Pet bluemoon = new Pet {Name = "Blue Moon", Owner = terry};
    Pet daisy = new Pet {Name = "Daisy", Owner = magnus};

    // Create two lists.
    List<Person> people = new List<Person> {magnus, terry, charlotte, arlene};
    List<Pet> pets = new List<Pet> {barley, boots, whiskers, bluemoon, daisy};

    var query = from person in people
        where person.ID == 4
        join pet in pets on person equals pet.Owner  into personpets
        from petOrNull in personpets.DefaultIfEmpty()
        select new { Person=person, Pet = petOrNull}; 



    foreach (var v in query )
    {
        Console.WriteLine("{0,-15}{1}", v.Person.FirstName + ":", (v.Pet == null ? "Does not Exist" : v.Pet.Name));
    }
}

// This code produces the following output:
//
// Magnus:        Daisy
// Terry:         Barley
// Terry:         Boots
// Terry:         Blue Moon
// Charlotte:     Whiskers
// Arlene:

이제 당신은 include elements from the left그 요소라도 has no matches in the right우리의 경우에Arlene 는 그가 오른쪽에 일치하지 않는 에도 검색했습니다.

여기 참조입니다

방법 : 왼쪽 외부 조인 수행 (C # 프로그래밍 가이드)


결과는 다음과 같아야합니다. Arlene : 존재하지 않음
user1169587

10

이것은 일반적인 형태입니다 (이미 다른 답변에서 제공 한 바와 같이)

var c =
    from a in alpha
    join b in beta on b.field1 equals a.field1 into b_temp
    from b_value in b_temp.DefaultIfEmpty()
    select new { Alpha = a, Beta = b_value };

그러나 이것이 실제로 이것이 의미하는 바를 분명히하기를 바랍니다.

join b in beta on b.field1 equals a.field1 into b_temp

본질적으로 오른쪽의 항목에 대한 null '행'( 'b'의 항목)을 효과적으로 포함하는 별도의 결과 집합 b_temp를 만듭니다.

다음 줄 :

from b_value in b_temp.DefaultIfEmpty()

.. 오른쪽에 'row'에 대한 기본 null 값을 설정하고 오른쪽 행 조인 결과를 'b_value'값 (예 : 오른쪽에있는 값)으로 설정하여 해당 결과 집합을 반복합니다. 일치하는 레코드가있는 경우, 그렇지 않으면 'null'입니다.

이제 오른쪽이 별도의 LINQ 쿼리의 결과 인 경우 익명 형식으로 구성되며 '무언가'또는 'null'만 가능합니다. 그러나 열거 할 수있는 경우 (예 : MyObjectB가 2 개의 필드가있는 클래스 인 목록) 속성에 사용되는 기본 'null'값에 대해 구체적으로 지정할 수 있습니다.

var c =
    from a in alpha
    join b in beta on b.field1 equals a.field1 into b_temp
    from b_value in b_temp.DefaultIfEmpty( new MyObjectB { Field1 = String.Empty, Field2 = (DateTime?) null })
    select new { Alpha = a, Beta_field1 = b_value.Field1, Beta_field2 = b_value.Field2 };

이렇게하면 'b'자체가 null이 아니므로 (지정한 기본 null 값을 사용하여 속성이 null 일 수 있음) b_value에 대한 null 참조 예외를받지 않고 b_value의 속성을 확인할 수 있습니다. 널 입력 가능 DateTime의 경우, 'DefaultIfEmpty'스펙에서 널 입력 가능 유형 인 (DateTime?), 즉 널 입력 가능 DateTime 유형을 널의 '유형'으로 지정해야합니다. 'nullable (예 : double, float).

위의 구문을 연결하여 여러 왼쪽 외부 조인을 수행 할 수 있습니다.


1
b_value는 어디에서 왔습니까?
잭 프레이저

9

다음은 두 개 이상의 테이블을 조인해야하는 예입니다.

from d in context.dc_tpatient_bookingd
join bookingm in context.dc_tpatient_bookingm 
     on d.bookingid equals bookingm.bookingid into bookingmGroup
from m in bookingmGroup.DefaultIfEmpty()
join patient in dc_tpatient
     on m.prid equals patient.prid into patientGroup
from p in patientGroup.DefaultIfEmpty()

참조 : https://stackoverflow.com/a/17142392/2343


4

Join 구문으로 왼쪽 조인처럼 작동하는 확장 방법

public static class LinQExtensions
{
    public static IEnumerable<TResult> LeftJoin<TOuter, TInner, TKey, TResult>(
        this IEnumerable<TOuter> outer, IEnumerable<TInner> inner, 
        Func<TOuter, TKey> outerKeySelector, 
        Func<TInner, TKey> innerKeySelector, 
        Func<TOuter, TInner, TResult> resultSelector)
    {
        return outer.GroupJoin(
            inner, 
            outerKeySelector, 
            innerKeySelector,
            (outerElement, innerElements) => resultSelector(outerElement, innerElements.FirstOrDefault()));
    }
}

방금 .NET 코어로 작성했으며 예상대로 작동하는 것 같습니다.

소규모 시험 :

        var Ids = new List<int> { 1, 2, 3, 4};
        var items = new List<Tuple<int, string>>
        {
            new Tuple<int, string>(1,"a"),
            new Tuple<int, string>(2,"b"),
            new Tuple<int, string>(4,"d"),
            new Tuple<int, string>(5,"e"),
        };

        var result = Ids.LeftJoin(
            items,
            id => id,
            item => item.Item1,
            (id, item) => item ?? new Tuple<int, string>(id, "not found"));

        result.ToList()
        Count = 4
        [0]: {(1, a)}
        [1]: {(2, b)}
        [2]: {(3, not found)}
        [3]: {(4, d)}

4

다음은 메소드 구문을 사용하여 버전을 이해하기 매우 쉽습니다.

IEnumerable<JoinPair> outerLeft =
    lefts.SelectMany(l => 
        rights.Where(r => l.Key == r.Key)
              .DefaultIfEmpty(new Item())
              .Select(r => new JoinPair { LeftId = l.Id, RightId = r.Id }));

3

3 개의 테이블이 있습니다 : person, school 및 persons_schools는 사람을 공부하는 학교와 연결합니다. id = 6 인 사람에 대한 참조는 테이블 people_schools에 없습니다. 그러나 id = 6 인 사람은 결과 lef-joined 격자에 표시됩니다.

List<Person> persons = new List<Person>
{
    new Person { id = 1, name = "Alex", phone = "4235234" },
    new Person { id = 2, name = "Bob", phone = "0014352" },
    new Person { id = 3, name = "Sam", phone = "1345" },
    new Person { id = 4, name = "Den", phone = "3453452" },
    new Person { id = 5, name = "Alen", phone = "0353012" },
    new Person { id = 6, name = "Simon", phone = "0353012" }
};

List<School> schools = new List<School>
{
    new School { id = 1, name = "Saint. John's school"},
    new School { id = 2, name = "Public School 200"},
    new School { id = 3, name = "Public School 203"}
};

List<PersonSchool> persons_schools = new List<PersonSchool>
{
    new PersonSchool{id_person = 1, id_school = 1},
    new PersonSchool{id_person = 2, id_school = 2},
    new PersonSchool{id_person = 3, id_school = 3},
    new PersonSchool{id_person = 4, id_school = 1},
    new PersonSchool{id_person = 5, id_school = 2}
    //a relation to the person with id=6 is absent
};

var query = from person in persons
            join person_school in persons_schools on person.id equals person_school.id_person
            into persons_schools_joined
            from person_school_joined in persons_schools_joined.DefaultIfEmpty()
            from school in schools.Where(var_school => person_school_joined == null ? false : var_school.id == person_school_joined.id_school).DefaultIfEmpty()
            select new { Person = person.name, School = school == null ? String.Empty : school.name };

foreach (var elem in query)
{
    System.Console.WriteLine("{0},{1}", elem.Person, elem.School);
}

이것은 아마도 질문에 대한 답변이 귀하의 답변에 대한 설명을 제공 할 것입니다 :)
Amir

2

내부 및 왼쪽 외부 조인의 LINQ 구문과 비교되는 SQL 구문입니다. 왼쪽 외부 조인 :

http://www.ozkary.com/2011/07/linq-to-entity-inner-and-left-joins.html

"다음 예는 제품과 범주 사이에 그룹 조인을 수행합니다. 기본적으로 왼쪽 조인입니다. into 표현식은 범주 테이블이 비어 있어도 데이터를 반환합니다. 범주 테이블의 속성에 액세스하려면 열거 가능한 결과에서 선택해야합니다. catList.DefaultIfEmpty () 문에 from cl을 추가하여


1

linq에서 왼쪽 외부 조인 수행 C # // 왼쪽 외부 조인 수행

class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

class Child
{
    public string Name { get; set; }
    public Person Owner { get; set; }
}
public class JoinTest
{
    public static void LeftOuterJoinExample()
    {
        Person magnus = new Person { FirstName = "Magnus", LastName = "Hedlund" };
        Person terry = new Person { FirstName = "Terry", LastName = "Adams" };
        Person charlotte = new Person { FirstName = "Charlotte", LastName = "Weiss" };
        Person arlene = new Person { FirstName = "Arlene", LastName = "Huff" };

        Child barley = new Child { Name = "Barley", Owner = terry };
        Child boots = new Child { Name = "Boots", Owner = terry };
        Child whiskers = new Child { Name = "Whiskers", Owner = charlotte };
        Child bluemoon = new Child { Name = "Blue Moon", Owner = terry };
        Child daisy = new Child { Name = "Daisy", Owner = magnus };

        // Create two lists.
        List<Person> people = new List<Person> { magnus, terry, charlotte, arlene };
        List<Child> childs = new List<Child> { barley, boots, whiskers, bluemoon, daisy };

        var query = from person in people
                    join child in childs
                    on person equals child.Owner into gj
                    from subpet in gj.DefaultIfEmpty()
                    select new
                    {
                        person.FirstName,
                        ChildName = subpet!=null? subpet.Name:"No Child"
                    };
                       // PetName = subpet?.Name ?? String.Empty };

        foreach (var v in query)
        {
            Console.WriteLine($"{v.FirstName + ":",-25}{v.ChildName}");
        }
    }

    // This code produces the following output:
    //
    // Magnus:        Daisy
    // Terry:         Barley
    // Terry:         Boots
    // Terry:         Blue Moon
    // Charlotte:     Whiskers
    // Arlene:        No Child

https://dotnetwithhamid.blogspot.in/


1

MoreLinq 확장을 얻으면 이제 동종 및 이종의 왼쪽 조인이 모두 지원됩니다.

http://morelinq.github.io/2.8/ref/api/html/Overload_MoreLinq_MoreEnumerable_LeftJoin.htm

예:

//Pretend a ClientCompany object and an Employee object both have a ClientCompanyID key on them

return DataContext.ClientCompany
    .LeftJoin(DataContext.Employees,                         //Table being joined
        company => company.ClientCompanyID,                  //First key
        employee => employee.ClientCompanyID,                //Second Key
        company => new {company, employee = (Employee)null}, //Result selector when there isn't a match
        (company, employee) => new { company, employee });   //Result selector when there is a match

편집하다:

돌이켜 보면 이것이 작동 할 수 있지만 morelinq는 쿼리를 SQL로 변환하지 않기 때문에 IQueryable을 IEnumerable로 변환합니다.

https://stackoverflow.com/a/24273804/4251433에 설명 된대로 GroupJoin을 대신 사용할 수 있습니다.

이렇게하면 나중에 추가 논리적 작업을 수행해야 할 경우 IQueryable로 유지됩니다.


1

쉬운 방법은 Let 키워드를 사용하는 것입니다. 이것은 나를 위해 작동합니다.

from AItem in Db.A
Let BItem = Db.B.Where(x => x.id == AItem.id ).FirstOrDefault() 
Where SomeCondition
Select new YourViewModel
{
    X1 = AItem.a,
    X2 = AItem.b,
    X3 = BItem.c
}

이것은 왼쪽 결합의 시뮬레이션입니다. B 테이블의 각 항목이 A item과 일치하지 않으면 BItem은 null을 반환합니다.


0

무언가를 결합하고 필터링해야하는 경우 결합 외부에서 수행 할 수 있습니다. 컬렉션을 만든 후 필터를 수행 할 수 있습니다.

이 경우 조인 조건 에서이 작업을 수행하면 반환되는 행이 줄어 듭니다.

삼항 조건이 사용됩니다 (= n == null ? "__" : n.MonDayNote,)

  • 객체가 null(너무 일치하지 않으면) 뒤에 나오는 것을 반환하십시오 ?. __이 경우

  • 그렇지는 후에 무엇 반환 :, n.MonDayNote.

내 자신의 문제로 시작한 다른 기고자에게 감사드립니다.


        var schedLocations = (from f in db.RAMS_REVENUE_LOCATIONS
              join n in db.RAMS_LOCATION_PLANNED_MANNING on f.revenueCenterID equals

                  n.revenueCenterID into lm

              from n in lm.DefaultIfEmpty()

              join r in db.RAMS_LOCATION_SCHED_NOTE on f.revenueCenterID equals r.revenueCenterID
              into locnotes

              from r in locnotes.DefaultIfEmpty()
              where f.LocID == nLocID && f.In_Use == true && f.revenueCenterID > 1000

              orderby f.Areano ascending, f.Locname ascending
              select new
              {
                  Facname = f.Locname,
                  f.Areano,
                  f.revenueCenterID,
                  f.Locabbrev,

                  //  MonNote = n == null ? "__" : n.MonDayNote,
                  MonNote = n == null ? "__" : n.MonDayNote,
                  TueNote = n == null ? "__" : n.TueDayNote,
                  WedNote = n == null ? "__" : n.WedDayNote,
                  ThuNote = n == null ? "__" : n.ThuDayNote,

                  FriNote = n == null ? "__" : n.FriDayNote,
                  SatNote = n == null ? "__" : n.SatDayNote,
                  SunNote = n == null ? "__" : n.SunDayNote,
                  MonEmpNbr = n == null ? 0 : n.MonEmpNbr,
                  TueEmpNbr = n == null ? 0 : n.TueEmpNbr,
                  WedEmpNbr = n == null ? 0 : n.WedEmpNbr,
                  ThuEmpNbr = n == null ? 0 : n.ThuEmpNbr,
                  FriEmpNbr = n == null ? 0 : n.FriEmpNbr,
                  SatEmpNbr = n == null ? 0 : n.SatEmpNbr,
                  SunEmpNbr = n == null ? 0 : n.SunEmpNbr,
                  SchedMondayDate = n == null ? dMon : n.MondaySchedDate,
                  LocNotes = r == null ? "Notes: N/A" : r.LocationNote

              }).ToList();
                Func<int, string> LambdaManning = (x) => { return x == 0 ? "" : "Manning:" + x.ToString(); };
        DataTable dt_ScheduleMaster = PsuedoSchedule.Tables["ScheduleMasterWithNotes"];
        var schedLocations2 = schedLocations.Where(x => x.SchedMondayDate == dMon);

0
class Program
{
    List<Employee> listOfEmp = new List<Employee>();
    List<Department> listOfDepart = new List<Department>();

    public Program()
    {
        listOfDepart = new List<Department>(){
            new Department { Id = 1, DeptName = "DEV" },
            new Department { Id = 2, DeptName = "QA" },
            new Department { Id = 3, DeptName = "BUILD" },
            new Department { Id = 4, DeptName = "SIT" }
        };


        listOfEmp = new List<Employee>(){
            new Employee { Empid = 1, Name = "Manikandan",DepartmentId=1 },
            new Employee { Empid = 2, Name = "Manoj" ,DepartmentId=1},
            new Employee { Empid = 3, Name = "Yokesh" ,DepartmentId=0},
            new Employee { Empid = 3, Name = "Purusotham",DepartmentId=0}
        };

    }
    static void Main(string[] args)
    {
        Program ob = new Program();
        ob.LeftJoin();
        Console.ReadLine();
    }

    private void LeftJoin()
    {
        listOfEmp.GroupJoin(listOfDepart.DefaultIfEmpty(), x => x.DepartmentId, y => y.Id, (x, y) => new { EmpId = x.Empid, EmpName = x.Name, Dpt = y.FirstOrDefault() != null ? y.FirstOrDefault().DeptName : null }).ToList().ForEach
            (z =>
            {
                Console.WriteLine("Empid:{0} EmpName:{1} Dept:{2}", z.EmpId, z.EmpName, z.Dpt);
            });
    }
}

class Employee
{
    public int Empid { get; set; }
    public string Name { get; set; }
    public int DepartmentId { get; set; }
}

class Department
{
    public int Id { get; set; }
    public string DeptName { get; set; }
}

산출


0

비슷한 질문에 대한 내 대답에 따라 여기 :

Linq to SQL은 Lambda 구문을 사용하고 2 개의 열에 결합하여 외부 결합을 남겼습니다 (복합 결합 키).

여기에서 코드를 얻으십시오 거나 github repo를 복제 하고 재생하십시오!

질문:

        var petOwners =
            from person in People
            join pet in Pets
            on new
            {
                person.Id,
                person.Age,
            }
            equals new
            {
                pet.Id,
                Age = pet.Age * 2, // owner is twice age of pet
            }
            into pets
            from pet in pets.DefaultIfEmpty()
            select new PetOwner
            {
                Person = person,
                Pet = pet,
            };

람다 :

        var petOwners = People.GroupJoin(
            Pets,
            person => new { person.Id, person.Age },
            pet => new { pet.Id, Age = pet.Age * 2 },
            (person, pet) => new
            {
                Person = person,
                Pets = pet,
            }).SelectMany(
            pet => pet.Pets.DefaultIfEmpty(),
            (people, pet) => new
            {
                people.Person,
                Pet = pet,
            });

0

개요 :이 코드 스 니펫에서는 Table1과 Table2가 일대 다 관계인 ID별로 그룹화하는 방법을 보여줍니다. Id, Field1 및 Field2를 그룹화합니다. 하위 쿼리는 세 번째 테이블 조회가 필요하고 왼쪽 조인 관계가 필요한 경우 유용합니다. 왼쪽 조인 그룹화와 하위 쿼리 linq를 보여줍니다. 결과는 동일합니다.

class MyView
{
public integer Id {get,set};
    public String Field1  {get;set;}
public String Field2 {get;set;}
    public String SubQueryName {get;set;}                           
}

IList<MyView> list = await (from ci in _dbContext.Table1
                                               join cii in _dbContext.Table2
                                                   on ci.Id equals cii.Id

                                               where ci.Field1 == criterion
                                               group new
                                               {
                                                   ci.Id
                                               } by new { ci.Id, cii.Field1, ci.Field2}

                                           into pg
                                               select new MyView
                                               {
                                                   Id = pg.Key.Id,
                                                   Field1 = pg.Key.Field1,
                                                   Field2 = pg.Key.Field2,
                                                   SubQueryName=
                                                   (from chv in _dbContext.Table3 where chv.Id==pg.Key.Id select chv.Field1).FirstOrDefault()
                                               }).ToListAsync<MyView>();


 Compared to using a Left Join and Group new

IList<MyView> list = await (from ci in _dbContext.Table1
                                               join cii in _dbContext.Table2
                                                   on ci.Id equals cii.Id

                       join chv in _dbContext.Table3
                                                  on cii.Id equals chv.Id into lf_chv
                                                from chv in lf_chv.DefaultIfEmpty()

                                               where ci.Field1 == criterion
                                               group new
                                               {
                                                   ci.Id
                                               } by new { ci.Id, cii.Field1, ci.Field2, chv.FieldValue}

                                           into pg
                                               select new MyView
                                               {
                                                   Id = pg.Key.Id,
                                                   Field1 = pg.Key.Field1,
                                                   Field2 = pg.Key.Field2,
                                                   SubQueryName=pg.Key.FieldValue
                                               }).ToListAsync<MyView>();

-1
(from a in db.Assignments
     join b in db.Deliveryboys on a.AssignTo equals b.EmployeeId  

     //from d in eGroup.DefaultIfEmpty()
     join  c in  db.Deliveryboys on a.DeliverTo equals c.EmployeeId into eGroup2
     from e in eGroup2.DefaultIfEmpty()
     where (a.Collected == false)
     select new
     {
         OrderId = a.OrderId,
         DeliveryBoyID = a.AssignTo,
         AssignedBoyName = b.Name,
         Assigndate = a.Assigndate,
         Collected = a.Collected,
         CollectedDate = a.CollectedDate,
         CollectionBagNo = a.CollectionBagNo,
         DeliverTo = e == null ? "Null" : e.Name,
         DeliverDate = a.DeliverDate,
         DeliverBagNo = a.DeliverBagNo,
         Delivered = a.Delivered

     });

-1

LEFT OUTER JOIN을 위한 간단한 솔루션 :

var setA = context.SetA;
var setB = context.SetB.Select(st=>st.Id).Distinct().ToList();
var leftOuter  = setA.Where(stA=> !setB.Contains(stA.Id)); 

참고 사항 :

  • 성능을 향상 시키려면 SetB를 Dictionary ( 변환 된 경우 ! setB.Contains (stA.Id) ) 또는 HashSet 로 변경해야합니다.
  • 관련된 필드가 둘 이상인 경우 Set 작업과 다음을 구현하는 클래스를 사용하여 달성 할 수 있습니다 . IEqualityComparer

왼쪽 외부가 일치 반환에 가입 setA하고 setB질문에 대해 답.
NetMage
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.