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 Join
dua daftar di Id
lapangan hasilnya adalah:
Value ChildValue
A a1
A a2
A a3
B b1
B b2
Ketika Anda GroupJoin
dua daftar di Id
lapangan hasilnya adalah:
Value ChildValues
A [a1, a2, a3]
B [b1, b2]
C []
Jadi Join
menghasilkan hasil datar (tabular) dari nilai induk dan anak.
GroupJoin
menghasilkan daftar entri dalam daftar pertama, masing-masing dengan sekelompok entri yang tergabung dalam daftar kedua.
Itu sebabnya Join
sama dengan INNER JOIN
di SQL: tidak ada entri untuk C
. Sedangkan GroupJoin
setara dengan OUTER JOIN
: C
ada 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, Value
dan ChildValue
. Sintaks kueri ini menggunakan Join
metode 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 Parent
dan properti tipe IEnumerable<Child>
. Sintaks kueri ini menggunakan GroupJoin
metode di bawah tenda.
Kita bisa melakukannya select g
di 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, join
pernyataan apa saja dapat dengan mudah dikonversi menjadi outer join
dengan menambahkan setara into g from c in g.DefaultIfEmpty()
dengan join
pernyataan 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 join
di 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 Id
nilai 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 parents
akan menentukan hasilnya. Jika orang tua diperintahkan oleh Id
, hasilnya adalah orang tua 2, 3, 4, 7. Tidak baik. Namun, kami juga dapat menggunakan join
untuk memfilter daftar. Dan dengan menggunakan ids
sebagai 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.