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.