Linq to Entities katılmak vs groupjoin


182

Web'de arama yaptım ancak hala basit bir cevap bulamıyorum. Birisi a'nın ne olduğunu açıklayabilir GroupJoinmi? Normal içten farkı Joinnedir? Yaygın olarak kullanılıyor mu? Sadece yöntem sözdizimi için mi? Sorgu sözdizimi ne olacak? Bir c # kodu örneği iyi olurdu.


MSDN'ye göre, bir grup birleşimi bir ifadeye sahip bir birleştirme cümlesidir. join yan tümcesi daha fazla bilgi ve kod örneğine sahiptir. Bu aslında bir iç birleşimdir (sağdaki hiçbir öğe soldaki herhangi bir öğe ile eşleşmezse, boş bir sonuç elde edersiniz); ancak sonuç gruplar halinde düzenlenir.
Tim

Yanıtlar:


375

davranış

İki listeniz olduğunu varsayalım:

Id  Value
1   A
2   B
3   C

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

Sahadaki Joiniki liste sizde Idsonuç olacaktır:

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

Sahadaki GroupJoiniki liste sizde Idsonuç olacaktır:

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

Böylece Join, üst ve alt değerlerin düz (tablo) bir sonucunu verir.
GroupJoinher biri ikinci listede birleştirilmiş bir grup girdi içeren ilk listede bir girdi listesi oluşturur.

Bu yüzden SQL'de Joineşdeğerdir INNER JOIN: için giriş yoktur C. While : sonuç kümesinde GroupJoineşdeğerdir , ancak ilgili girdilerin boş bir listesiyle (SQL sonuç kümesinde bir satır olacaktır ).OUTER JOINCC - null

Sözdizimi

Öyleyse iki liste sırasıyla IEnumerable<Parent>ve olsun IEnumerable<Child>. (Linq to Entities için:) IQueryable<T>.

Join sözdizimi

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

Bir dönen IEnumerable<X>nerede X iki özelliklere sahip bir anonim türüdür Valueve ChildValue. Bu sorgu sözdizimi Joinbaşlık altındaki yöntemi kullanır .

GroupJoin sözdizimi

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

An dönen IEnumerable<Y>Y, bir tür özelliği aşağıdakilerden oluşan anonim türüdür Parentve tip bir özelliği IEnumerable<Child>. Bu sorgu sözdizimi GroupJoinbaşlık altındaki yöntemi kullanır .

Biz sadece yapabileceği select gbir seçersiniz ikinci sorguda, içinde IEnumerable<IEnumerable<Child>>, listelerin listesi söylüyorlar. Çoğu durumda, ebeveynin dahil olduğu seçim daha yararlıdır.

Bazı kullanım durumları

1. Düz bir dış birleşim oluşturmak.

Dediğim gibi, açıklama ...

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

... çocuk gruplarına sahip bir ebeveyn listesi oluşturur. Bu, iki küçük ilavelerle düz bir ebeveyn-çocuk çifti listesine dönüştürülebilir:

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 }

Sonuç şuna benzer

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

Aralık değişkeninin c yukarıdaki ifadede yeniden kullanıldığını unutmayın . Bunu yaparak, herhangi bir joinaçıklama basitçe bir dönüştürülmüş olabilir outer joineşdeğer ekleyerek into g from c in g.DefaultIfEmpty()varolan için joindeyimi.

Bu, sorgu (veya kapsamlı) sözdiziminin parladığı yerdir. Yöntem (veya akıcı) sözdizimi gerçekten ne olduğunu gösterir, ancak yazmak zor:

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

Yani outer joinLINQ'da bir daire GroupJoin, düzleştirilmiş bir SelectMany.

2. sipariş koruma

Ebeveyn listesinin biraz daha uzun olduğunu varsayalım. Bazı kullanıcı arabirimleri, seçilen ana öğelerin listesini Idsabit bir sırada değerler olarak üretir . Kullanalım:

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

Şimdi seçilen ebeveynler ebeveyn listesinden bu sırayla filtrelenmelidir.

Eğer yaparsak ...

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

... sonucu sırası parentsbelirleyecektir. Ebeveynler tarafından sipariş edilirse, Idsonuç ebeveynler 2, 3, 4, 7 olacaktır. İyi değil. Ancak, joinlisteyi filtrelemek için de kullanabiliriz . Ve idsilk liste olarak kullanarak , sipariş korunacaktır:

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

Sonuç ebeveynler 3, 7, 2, 4'tür.


Bir GroupJoin içinde, alt değerler ilgili değerleri içeren nesneleri içerir?
duyn9uyen

Dediğiniz gibi GroupJoin bir dış birleşim gibidir ancak sözdizimi (tamamen grup birleşimi için linq) dış birleşim değil sol dış birleşim gibi olduğunu söyler.
İmad

2
Sanırım "Düz Dış Birleştirme" nin bir Sol Dış Birleştirme olduğunu belirtirdim.
NetMage

1
Mükemmel
açıkladı

19

EduLINQ göre :

GroupJoin'in yaptıklarını kavramanın en iyi yolu Üyelik düşünmektir. Burada genel fikir, "dış" girdi dizisine baktığımız, "iç" diziden eşleşen tüm öğeleri bulduğumuz (her bir dizideki önemli bir projeksiyona dayanarak) ve daha sonra eşleşen element çiftleri verdiğiydi. GroupJoin benzerdir, ancak eleman çiftlerini vermek yerine, o öğeye ve eşleşen "iç" öğelerin sırasına göre her "dış" öğe için tek bir sonuç verir .

Tek fark dönüş ifadesinde:

Katılın :

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

Grup Katıl :

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

Daha fazlasını buradan okuyun:

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.