Verhalten
Angenommen, Sie haben zwei Listen:
Id Value
1 A
2 B
3 C
Id ChildValue
1 a1
1 a2
1 a3
2 b1
2 b2
Wenn Sie Join
die beiden Listen auf dem Id
Feld haben, wird das Ergebnis sein:
Value ChildValue
A a1
A a2
A a3
B b1
B b2
Wenn Sie GroupJoin
die beiden Listen auf dem Id
Feld haben, wird das Ergebnis sein:
Value ChildValues
A [a1, a2, a3]
B [b1, b2]
C []
So Join
ergibt sich eine flache (tabellarische) Ergebnis von Eltern und Kind Werte.
GroupJoin
Erzeugt eine Liste von Einträgen in der ersten Liste mit jeweils einer Gruppe von verbundenen Einträgen in der zweiten Liste.
Aus diesem Grund Join
entspricht dies INNER JOIN
SQL: Es gibt keine Einträge für C
. Während GroupJoin
ist das Äquivalent von OUTER JOIN
: C
ist in der Ergebnismenge, aber mit einer leeren Liste verwandter Einträge (in einer SQL-Ergebnismenge würde es eine Zeile geben C - null
).
Syntax
Also lassen Sie die beiden Listen sein IEnumerable<Parent>
und IEnumerable<Child>
jeweils. (Im Fall von Linq to Entities :) IQueryable<T>
.
Join
Syntax wäre
from p in Parent
join c in Child on p.Id equals c.Id
select new { p.Value, c.ChildValue }
Rückgabe eines IEnumerable<X>
wobei X ein anonymer Typ mit zwei Eigenschaften ist, Value
und ChildValue
. Diese Abfragesyntax verwendet die Join
Methode unter der Haube.
GroupJoin
Syntax wäre
from p in Parent
join c in Child on p.Id equals c.Id into g
select new { Parent = p, Children = g }
Rückgabe eines IEnumerable<Y>
wobei Y ein anonymer Typ ist, der aus einer Eigenschaft des Typs Parent
und einer Eigenschaft des Typs besteht IEnumerable<Child>
. Diese Abfragesyntax verwendet die GroupJoin
Methode unter der Haube.
Wir könnten einfach select g
in der letzteren Abfrage IEnumerable<IEnumerable<Child>>
eine Liste von Listen auswählen . In vielen Fällen ist die Auswahl mit dem übergeordneten Element nützlicher.
Einige Anwendungsfälle
1. Herstellen einer flachen äußeren Verbindung.
Wie gesagt, die Aussage ...
from p in Parent
join c in Child on p.Id equals c.Id into g
select new { Parent = p, Children = g }
... erstellt eine Liste der Eltern mit Kindergruppen. Dies kann durch zwei kleine Ergänzungen in eine flache Liste von Eltern-Kind-Paaren umgewandelt werden:
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 }
Das Ergebnis ist ähnlich wie
Value Child
A a1
A a2
A a3
B b1
B b2
C (null)
Beachten Sie, dass die Bereichsvariable c
in der obigen Anweisung wiederverwendet wird. Auf diese Weise kann jede join
Anweisung einfach in eine konvertiert werden, outer join
indem das Äquivalent into g from c in g.DefaultIfEmpty()
zu einer vorhandenen join
Anweisung hinzugefügt wird .
Hier setzt die Abfragesyntax (oder umfassende Syntax) an. Die Methodensyntax (oder die fließende Syntax) zeigt, was wirklich passiert, aber es ist schwer zu schreiben:
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 } )
Eine Wohnung outer join
in LINQ ist also eine GroupJoin
, abgeflacht von SelectMany
.
2. Ordnung bewahren
Angenommen, die Liste der Eltern ist etwas länger. Einige Benutzeroberflächen erstellen eine Liste ausgewählter Eltern als Id
Werte in einer festen Reihenfolge. Verwenden wir:
var ids = new[] { 3,7,2,4 };
Jetzt müssen die ausgewählten Eltern in genau dieser Reihenfolge aus der Elternliste herausgefiltert werden.
Wenn wir es tun ...
var result = parents.Where(p => ids.Contains(p.Id));
... bestimmt die Reihenfolge des parents
Willens das Ergebnis. Wenn die Eltern von bestellt werden Id
, sind die Eltern 2, 3, 4, 7. Das Ergebnis ist nicht gut. Wir können jedoch auch join
die Liste filtern. Durch die Verwendung ids
als erste Liste bleibt die Reihenfolge erhalten:
from id in ids
join p in parents on id equals p.Id
select p
Das Ergebnis sind die Eltern 3, 7, 2, 4.