Linq to Entities gabung vs groupjoin

182

Saya telah mencari di web tetapi saya masih tidak dapat menemukan jawaban yang sederhana. Bisakah seseorang tolong jelaskan (dalam bahasa Inggris sederhana) apa GroupJoinitu? Apa bedanya dengan batin yang biasa Join? Apakah ini biasa digunakan? Apakah hanya untuk sintaksis metode? Bagaimana dengan sintaks query? Contoh kode c # akan menyenangkan.

duyn9uyen
sumber
Menurut MSDN, gabungan grup adalah klausa gabungan dengan ekspresi menjadi. join clause memiliki lebih banyak informasi dan contoh kode. Ini pada dasarnya gabungan batin (jika tidak ada elemen di kanan yang cocok dengan apa pun di sebelah kiri, Anda mendapatkan hasil nol); namun hasilnya diatur dalam kelompok.
Tim

Jawaban:

375

Tingkah laku

Misalkan Anda memiliki dua daftar:

Id  Value
1   A
2   B
3   C

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

Ketika Anda Joindua daftar di Idlapangan hasilnya adalah:

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

Ketika Anda GroupJoindua daftar di Idlapangan hasilnya adalah:

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

Jadi Joinmenghasilkan hasil datar (tabular) dari nilai induk dan anak.
GroupJoinmenghasilkan daftar entri dalam daftar pertama, masing-masing dengan sekelompok entri yang tergabung dalam daftar kedua.

Itu sebabnya Joinsama dengan INNER JOINdi SQL: tidak ada entri untuk C. Sedangkan GroupJoinsetara dengan OUTER JOIN: Cada di set hasil, tetapi dengan daftar kosong entri terkait (dalam set hasil SQL akan ada baris C - null).

Sintaksis

Jadi, biarkan kedua daftar itu menjadi IEnumerable<Parent>dan IEnumerable<Child>masing - masing. (Dalam hal Linq ke Entitas:) IQueryable<T>.

Join sintaks akan menjadi

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

mengembalikan IEnumerable<X>X di mana adalah jenis anonim dengan dua properti, Valuedan ChildValue. Sintaks kueri ini menggunakan Joinmetode di bawah tenda.

GroupJoin sintaks akan menjadi

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

mengembalikan suatu IEnumerable<Y>tempat Y adalah tipe anonim yang terdiri dari satu properti tipe Parentdan properti tipe IEnumerable<Child>. Sintaks kueri ini menggunakan GroupJoinmetode di bawah tenda.

Kita bisa melakukannya select gdi kueri terakhir, yang akan memilih IEnumerable<IEnumerable<Child>>, katakan daftar daftar. Dalam banyak kasus, pilih dengan induk yang disertakan lebih bermanfaat.

Beberapa menggunakan case

1. Memproduksi sambungan luar yang rata.

Seperti yang dikatakan, pernyataan ...

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

... menghasilkan daftar orang tua dengan kelompok anak. Ini dapat diubah menjadi daftar datar pasangan orangtua-anak dengan dua tambahan kecil:

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 }

Hasilnya mirip dengan

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

Perhatikan bahwa variabel rentang c digunakan kembali dalam pernyataan di atas. Melakukan hal ini, joinpernyataan apa saja dapat dengan mudah dikonversi menjadi outer joindengan menambahkan setara into g from c in g.DefaultIfEmpty()dengan joinpernyataan yang ada .

Di sinilah sintaks kueri (atau komprehensif) bersinar. Sintaksis metode (atau fasih) menunjukkan apa yang sebenarnya terjadi, tetapi sulit untuk menulis:

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

Jadi flat outer joindi LINQ adalah GroupJoin, diratakan oleh SelectMany.

2. Mempertahankan pesanan

Misalkan daftar orang tua sedikit lebih lama. Beberapa UI menghasilkan daftar orang tua yang dipilih sebagai Idnilai dalam urutan tetap. Mari kita gunakan:

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

Sekarang orang tua yang dipilih harus disaring dari daftar orang tua dalam urutan yang tepat ini.

Jika kita ...

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

... urutan parentsakan menentukan hasilnya. Jika orang tua diperintahkan oleh Id, hasilnya adalah orang tua 2, 3, 4, 7. Tidak baik. Namun, kami juga dapat menggunakan joinuntuk memfilter daftar. Dan dengan menggunakan idssebagai daftar pertama, pesanan akan dipertahankan:

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

Hasilnya adalah orang tua 3, 7, 2, 4.

Gert Arnold
sumber
Jadi dalam GroupJoin, nilai-nilai anak akan berisi objek, yang berisi nilai-nilai terkait?
duyn9uyen
Seperti yang Anda katakan, GroupJoin seperti gabungan luar tetapi sintaks itu (murni linq untuk grup bergabung) mengatakan itu bukan seperti gabungan luar tetapi gabungan luar kiri.
Imad
2
Saya pikir saya akan menentukan bahwa "Flat Outer Join" adalah Left Outer Join.
NetMage
1
Dijelaskan dengan sempurna, saya sekarang mengerti
peterincumbria
19

Menurut eduLINQ :

Cara terbaik untuk memahami apa yang dilakukan GroupJoin adalah memikirkan Bergabung. Di sana, ide keseluruhannya adalah bahwa kita melihat melalui urutan input "luar", menemukan semua item yang cocok dari urutan "dalam" (berdasarkan pada proyeksi kunci pada setiap urutan) dan kemudian menghasilkan pasangan elemen yang cocok. GroupJoin serupa, kecuali bahwa alih-alih menghasilkan pasangan elemen, itu menghasilkan hasil tunggal untuk setiap item "luar" berdasarkan item itu dan urutan pencocokan item "dalam" .

Satu-satunya perbedaan adalah dalam pernyataan pengembalian:

Bergabunglah :

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

GroupJoin :

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

Baca lebih lanjut di sini:

MarcinJuraszek
sumber