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.