LINQ'DA SOL DIŞ KATILIM


539

C # LINQ'da sol dış birleşimi join-on-equals-intocümle kullanmadan nesnelere nasıl uygulayabilirim ? Bunu wheremadde ile yapmanın bir yolu var mı ? Doğru sorun: İç birleşim için kolay ve böyle bir çözümüm var

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})

ama sol dış birleşim için bir çözüme ihtiyacım var. Benimki böyle bir şey ama çalışmıyor

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
                                        })

Burada JoinPair bir sınıftır:

public class JoinPair { long leftId; long rightId; }

2
elde etmeye çalıştığınız şeyin bir örneğini verebilir misiniz?
jeroenh

normal sol dış birleşim şöyledir: var a = bb'deki b'den b birleşiminde b.bbbbb üzerindeki cc'de c.ccccc, dd'deki d'den dd'ye eşittir.DefaultIfEmpty () select b.sss; Benim soru bu witouth birleştirme-eşittir-yan tümceleri cümle kullanarak yapmak için herhangi bir yolu var böyle bir şey var a = b bb bb c cc cc b.bbb == c.cccc ... ve böylece .. .
Oyuncak

1
olduğundan emin olun, ancak insanların size daha iyi bir cevap verebilmesi için kodunuzun bir örneğini göndermelisiniz
tembellik

Bir " Hariç tutulan " BİRLEŞME arıyordum (ve "DIŞ" kavramıyla karıştırdım). Bu cevap istediğime daha yakındı.
Kırmızı Bezelye

Yanıtlar:


598

Belirtildiği gibi:

101 LINQ Örnekleri - Sol dış birleşim

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
Aynı şeyi deniyorum ama birleştirme işlecinde "birleştirme yan tümcesindeki ifadelerden biri yanlış." Yazan bir hata alıyorum.
Badhon Jain

3
@jain türleriniz farklıysa birleştirme çalışmaz. Büyük olasılıkla anahtarlarınız farklı veri türlerine sahiptir. Her iki anahtar da int mi?
Yooakim

2
Çözüm Jain nedir? Ben de aynı hatayla karşılaşıyorum ve tipler benim durumumda da aynı.
Sandeep

1
@ Anahtarlarınızı katıldığınız yere kontrol edin. Diyelim ki bunlar string ve int türündeyse dize anahtarını int'e dönüştürün.
Ankit

2
güncellenmiş bağlantı: 101 LINQ Örnekleri - Sol dış birleşim
BukeMan

546

Veri tabanı güdümlü bir LINQ sağlayıcısı kullanılırsa, çok daha okunabilir bir sol dış birleşim şu şekilde yazılabilir:

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

Eğer atlarsanız, DefaultIfEmpty()bir iç birleşim olacaktır.

Kabul edilen cevabı al:

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

Bu sözdizimi çok kafa karıştırıcı ve MULTIPLE tablolarına katılmak istediğinizde nasıl çalıştığı belli değil.

Not
Dikkat edilmelidir kifrom alias in Repo.whatever.Where(condition).DefaultIfEmpty() Satır başına tanımadığınız sürece herhangi bir (iyi) veritabanı optimize edicisinin sol birleşmeye mükemmel bir şekilde dönüşebildiği bir dış uygulama / sol birleştirme yanalıyla aynı olduğu değerleri (gerçek bir dış uygulama olarak da bilinir). Linq-2-Objects bunu yapmayın (çünkü Linq-to-Objects kullandığınızda DB-optimizer yok).

Ayrıntılı Örnek

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 ile birlikte kullanıldığında, aşağıdaki çok okunaklı SQL sorgusuna hoş bir şekilde tercüme edilecektir:

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

Düzenle:

Daha karmaşık bir örnek için ayrıca bkz. " SQL Server sorgusunu Linq sorgusuna dönüştürme ".

Ayrıca, Linq-2-Objects (Linq-2-SQL yerine) içinde yapıyorsanız, bunu eski moda bir şekilde yapmalısınız (çünkü LINQ to SQL, işlemleri birleştirmek için bunu doğru bir şekilde çevirir, ancak nesneler bu yöntem üzerine tam bir taramayı zorlar ve endeks aramalarından yararlanmaz, neden olsa ...):

    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
Bu cevap aslında faydalıdır. Aslında anlaşılabilir bir sözdizimi sunduğunuz için teşekkür ederiz.
Chris Marisic

3
NHibernate uyumlu bir LINQ sorgusu
wTB

30
LINQ to SQL, işlemleri birleştirmek için bunu doğru şekilde çevirir. Nesnelerin üzerinde ancak bu yöntem tam bir taramayı zorlar, Bu nedenle resmi belgeler, aramalara indekslemek için karmalardan yararlanabilecek grup birleştirme çözümü sunar.
Tamir Daniely

3
Açık sözdizimi joinçok daha okunaklı ve net olduğunu düşünüyorum bir wheretakipDefaultIfEmpty
FindOut_Quran

1
@ user3441905: Tablo a ile tablo b'yi birleştirmeniz gerektiği sürece bu olabilir. Ama bundan daha fazlasına sahip olur olmaz, olmayacak. Ama sadece 2 tablo için bile, bence aşırı verbous. Popüler cevap da size karşı gibi görünüyor, çünkü bu cevap en üstteki cevap zaten 90'dan fazla oy aldığında 0 ile başladı.
Stefan Steiger

132

Lambda ifadesini kullanma

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
Hem Join hem de GroupJoin, sol üyeliği gerçekten desteklemiyor. GroupJoin kullanmanın püf noktası, boş gruplara sahip olabilmeniz ve bu boş grupları boş değerlere çevirebilmenizdir. DefaultIfEmpty basitçe bunu yapar, yani Enumerable.Empty<Product>.DefaultIfEmpty()tek bir değeri olan bir IEnumerable döndürür default(Product).
Tamir Daniely

61
Tüm bunlar sol birleştirme gerçekleştirmek için ??
FindOut_Quran

7
Bunun için teşekkürler! Çok fazla lambda ifadesi örneği yok, bu benim için çalıştı.
Johan Henkens

1
Cevap için teşekkürler. Yıllar boyunca yazdığım ham SQL SOL
DIER JOIN'e

1
Son Seçime () gerçekten gerek yok, SelectMany () içindeki anon obj aynı çıktı için yeniden düzenlenebilir. Başka bir düşünce, y'yi daha yakın bir LEFT JOIN eşdeğerini simüle etmek için null için test etmektir.
Denny Jacob

46

Şimdi bir uzantı yöntemi olarak:

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));
    }
}

Normalde join kullanacağınız gibi kullanın:

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

Umarım bu size biraz zaman kazandırır.


44

Bu örneğe bir göz atın . Bu sorgu çalışmalıdır:

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
Can rbir içine katılmak kullandıktan sonra seçme fıkrada erişilebilir?
Farhad Alizadeh Noori

@FarhadAlizadehNoori Evet Yapabilir.
Po-ta-toe

Yazar muhtemelen rikinci fromfıkrada yeniden kullanmak istiyordu . yani from r in lrs.DefaultIfEmpty()Aksi halde bu sorgu çok mantıklı değil ve belki de nedeni derleme değil rselect için bağlam dışı olmak.
Saeb Amini

@Devart, sorgunuzu okuduğumda bana ClockwiseJohn Cleese ile film hatırlattı , lol.
Matas Vaitkevicius

1
LeftRights soldaki haklarında leftrights içine sağa sola itibaren ... Ah tanrım ... sol dış kullanmanın sözdizimi LINQ JOIN gerçekten belli değil, ama bu isimler gerçekten daha da belirsiz hale.
Mike Gledhill

19

Genişletme yöntemleriyle sol dış birleştirmenin uygulanması aşağıdaki gibi görünebilir

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));
     }
   }

Sonuç seçici daha sonra boş elemanlara dikkat etmek zorundadır. 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
Ancak, bu yalnızca nesnelere LINQ için bir seçenektir ve sorguyu bu işlem için en yaygın kullanım durumu olan sorgu sağlayıcılarına çeviremez.
Mart'ta Servet

13
Ama soru "C # LINQ'da nesnelere sol dış birleşim nasıl yapılır ..."
Bertrand

12

bu örneğe bak

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:

şimdi include elements from the leftbu öğe olsa bile has no matches in the right, bizim durumumuzda Arlenesağda eşleşmesi olmasa bile geri döndük

işte referans

Nasıl yapılır: Sol Dış Birleştirmeleri Yapma (C # Programlama Kılavuzu)


çıktı şu şekilde olmalıdır: Arlene: Var değil
user1169587 29:18

10

Bu genel biçimdir (diğer cevaplarda zaten belirtildiği gibi)

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 };

Ancak, bunun gerçekte ne anlama geldiğini açıklayacağını umduğum bir açıklama var!

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

aslında sağ taraftaki girişler için etkin 'boş' satırları içeren ayrı bir sonuç kümesi b_temp oluşturur ('b' girişleri).

Sonra bir sonraki satır:

from b_value in b_temp.DefaultIfEmpty()

.. sağ taraftaki 'satır' için varsayılan boş değeri ayarlayarak ve sağ taraftaki satır birleşiminin sonucunu 'b_value' değerine (yani sağdaki değer) ayarlayarak eşleşen taraf varsa, veya yoksa 'null').

Şimdi, sağ taraf ayrı bir LINQ sorgusunun sonucuysa, yalnızca 'bir şey' veya 'boş' olabilen anonim türlerden oluşacaktır. Bununla birlikte numaralandırılabilirse (örneğin, bir List - burada MyObjectB, 2 alana sahip bir sınıftır), özellikleri için hangi varsayılan 'null' değerlerinin kullanıldığı konusunda spesifik olmak mümkündür:

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 };

Bu, 'b' öğesinin kendisinin boş olmamasını sağlar (ancak belirttiğiniz varsayılan boş değerleri kullanarak özellikleri boş olabilir) ve bu, b_value için boş bir başvuru istisnası almadan b_value özelliklerini denetlemenizi sağlar. Null olabilecek bir DateTime için, bir tür (DateTime?) Yani 'nullable DateTime' türünün 'DefaultIfEmpty' belirtimindeki null değerinin 'Type' olarak belirtilmesi gerektiğini unutmayın (bu aynı zamanda 'doğal olarak' olmayan türler için de geçerlidir nullable örn. çift, float).

Yukarıdaki sözdizimini zincirleyerek birden fazla sol dış birleşim gerçekleştirebilirsiniz.


1
b_value nereden geliyor?
Jack Fraser

9

2'den fazla masaya katılmanız gerekirse bir örnek:

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()

Referans: https://stackoverflow.com/a/17142392/2343


4

Join sözdizimi ile sol birleştirme gibi çalışan uzantı yöntemi

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()));
    }
}

sadece .NET çekirdeğinde yazdı ve beklendiği gibi çalışıyor gibi görünüyor.

Küçük test:

        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

Yöntem sözdizimini kullanarak anlaşılması oldukça kolay bir sürüm:

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

Üç tablo vardır: kişileri çalıştıkları okullara bağlayan kişiler, okullar ve kişiler_okulları. İd = 6 olan kişiye referans tablo_ kişiler tablosunda yoktur. Ancak id = 6 değerine sahip kişi sonuçta birleştirilen ızgarada sunulur.

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);
}

Bu belki de sorunun cevabı cevabınız hakkında bazı açıklamalar sağlar :)
Amir

2

Bu, iç ve sol dış birleşimler için LINQ sözdizimine kıyasla bir SQL sözdizimidir. Sol dış katılma:

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

"Aşağıdaki örnek, bir grup ürün ve kategori arasında birleşir. Bu, esasen sol birleşimdir. İfade içine, kategori tablosu boş olsa bile verileri döndürür. Kategori tablosunun özelliklerine erişmek için, şimdi numaralandırılabilir sonuçtan seçim yapmalıyız catList.DefaultIfEmpty () deyiminde from cl ekleyerek.


1

C # // sol dış birleşimlerini yapın Sol dış birleşimleri yapın

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 uzantısını alırsanız şimdi hem homojen hem de heterojen sol birleşimler için destek olduğunu eklemek istiyorum

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

misal:

//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

DÜZENLE:

Geriye bakıldığında bu işe yarayabilir, ancak morelinq sorguyu SQL'e dönüştürmediği için IQueryable'ı bir IEnumerable'a dönüştürür.

Bunun yerine burada açıklandığı gibi bir GroupJoin kullanabilirsiniz: https://stackoverflow.com/a/24273804/4251433

Bu, daha sonra daha fazla mantıksal işlem yapmanız gerektiğinde IQueryable olarak kalmasını sağlayacaktır.


1

Kolay yolu Let anahtar kelime kullanmaktır. Bu benim için çalışıyor.

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
}

Bu, Sol Birleşmenin simülasyonudur. B tablosundaki her öğe A öğesiyle eşleşmezse, BItem null değerini döndürür


0

Bir şeye katılmanız ve bir şeye filtre uygulamanız gerekiyorsa, bu birleştirme dışında yapılabilir. Filtre, koleksiyon oluşturulduktan sonra yapılabilir.

Bu durumda bunu birleştirme koşulunda yaparsam, döndürülen satırları azaltırım.

Üçlü durum kullanılır (= n == null ? "__" : n.MonDayNote,)

  • Nesne null(eşleşme yoksa) ise ?,. __, bu durumda.

  • Else, sonra ne dönmek :, n.MonDayNote.

Kendi sayımla başladığım diğer katkıda bulunanlar sayesinde.


        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; }
}

ÇIKTI


0

Benzer bir soruya verdiğim cevaba göre, burada:

Linq to SQL, Lambda sözdizimini kullanarak ve 2 sütunda birleştirme (bileşik birleştirme anahtarı)

Kodu buradan alın veya github repo'yu kopyalayın ve oynayın!

Sorgu:

        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,
            };

Lambda:

        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

Genel Bakış: Bu kod snippet'inde, Tablo1 ve Tablo2'nin bire çok ilişkisine sahip olduğu kimliğe göre nasıl gruplandırılacağını göstereceğim. Id, Field1 ve Field2 üzerinde gruplandırıyorum. Üçüncü bir Tablo araması gerekiyorsa ve bir sol birleştirme ilişkisi gerektiriyorsa alt sorgu yardımcı olur. Sol birleştirme gruplaması ve bir alt sorgu linq gösteririm. Sonuçlar eşdeğerdir.

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

SOL DIŞ birleşim için basit çözüm :

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

notlar :

  • Bir dönüştürülmüş olabilir performans SetB iyileştirmek için Sözlük (yani yapılırsa, bu durumda bunu değiştirmek zorunda: ! SetB.Contains (stA.Id) ) ya da bir HashSet
  • Birden fazla alan söz konusu olduğunda, Set işlemleri ve aşağıdakileri uygulayan bir sınıf kullanılarak bu gerçekleştirilebilir: IEqualityComparer

Sol dış birleşim eşleşmeyi setAve setBcevabı döndürür .
NetMage
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.