Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Die join
Klausel ist nützlich zum Zuordnen von Elementen aus verschiedenen Quellsequenzen, die keine direkte Beziehung im Objektmodell aufweisen. Die einzige Anforderung besteht darin, dass die Elemente in jeder Quelle einen Wert teilen, der für die Gleichheit verglichen werden kann. Beispielsweise kann ein Lebensmittelhändler eine Liste der Lieferanten eines bestimmten Produkts und eine Liste der Käufer haben. Eine join
Klausel kann z. B. verwendet werden, um eine Liste der Lieferanten und Käufer dieses Produkts zu erstellen, die sich alle in derselben angegebenen Region befinden.
Eine join
Klausel akzeptiert zwei Quellsequenzen als Eingabe. Die Elemente in jeder Sequenz müssen entweder eine Eigenschaft sein oder enthalten, die mit einer entsprechenden Eigenschaft in der anderen Sequenz verglichen werden kann. Die join
Klausel vergleicht die angegebenen Schlüssel für die Gleichheit mithilfe des speziellen equals
Schlüsselworts. Alle verknüpfungen, die von der join
Klausel ausgeführt werden, sind Equijoins. Die Form der Ausgabe einer join
Klausel hängt vom jeweiligen Typ der Verknüpfung ab, die Sie ausführen. Es folgen drei am häufigsten verwendete Verknüpfungstypen:
Innerer Join
Gruppenverknüpfung
Linker äußerer Join
Innerer Join
Im folgenden Beispiel wird eine einfache Gleichheitsverknüpfung dargestellt. Diese Abfrage erzeugt eine flache Sequenz von "Produktname/Kategorie"-Paaren. Dieselbe Kategoriezeichenfolge wird in mehreren Elementen angezeigt. Wenn ein Element aus categories
kein passendes products
hat, wird diese Kategorie nicht in den Ergebnissen angezeigt.
var innerJoinQuery =
from category in categories
join prod in products on category.ID equals prod.CategoryID
select new { ProductName = prod.Name, Category = category.Name }; //produces flat sequence
Weitere Informationen finden Sie unter Ausführen innerer Verknüpfungen.
Gruppe beitreten
Eine join
-Klausel mit einem into
-Ausdruck wird Gruppenverknüpfung genannt.
var innerGroupJoinQuery =
from category in categories
join prod in products on category.ID equals prod.CategoryID into prodGroup
select new { CategoryName = category.Name, Products = prodGroup };
Eine Gruppenbeitritt erzeugt eine hierarchische Ergebnissequenz, die Elemente in der linken Quellsequenz einem oder mehreren übereinstimmenden Elementen in der rechten Quellsequenz zuordnet. Ein Gruppenbeitritt hat keine Entsprechung in relationalen Ausdrücken; Es handelt sich im Wesentlichen um eine Abfolge von Objektarrays.
Wenn keine Elemente aus der richtigen Quellsequenz gefunden werden, um einem Element in der linken Quelle zu entsprechen, erzeugt die join
Klausel ein leeres Array für dieses Element. Deshalb ist eine Gruppenverknüpfung immer noch grundsätzlich eine innere Gleichheitsverknüpfung, nur dass die Ergebnissequenz in Gruppen aufgeteilt ist.
Wenn Sie nur die Ergebnisse eines Gruppenbeitritts auswählen, können Sie auf die Elemente zugreifen, aber Sie können den Schlüssel, für den sie übereinstimmen, nicht identifizieren. Deshalb ist es im Allgemeinen sinnvoller, das Ergebnis der Gruppenverknüpfung in einem neuen Typen auszuwählen, der auch einen Schlüsselnamen aufweist – so wie im vorherigen Ergebnis erläutert.
Sie können natürlich auch das Ergebnis einer Gruppenbeitritts als Generator einer anderen Unterabfrage verwenden:
var innerGroupJoinQuery2 =
from category in categories
join prod in products on category.ID equals prod.CategoryID into prodGroup
from prod2 in prodGroup
where prod2.UnitPrice > 2.50M
select prod2;
Weitere Informationen finden Sie unter "Gruppierte Verknüpfungen ausführen".
Linker äußerer Join
In einer linken äußeren Verknüpfung werden alle Elemente in der linken Quellsequenz zurückgegeben, auch wenn sich keine übereinstimmenden Elemente in der rechten Sequenz befinden. Verwenden Sie die DefaultIfEmpty
Methode in LINQ in Kombination mit einer Gruppenverknüpfung, um eine linke äußere Verknüpfung auszuführen, bei der ein standardmäßiges rechtsseitiges Element angegeben wird, das erzeugt werden soll, wenn ein linksseitiges Element keine Übereinstimmungen aufweist. Sie können null
als Standardwert für einen beliebigen Verweistyp verwenden oder einen benutzerdefinierten Standardtyp angeben. Im folgenden Beispiel wird ein benutzerdefinierter Standardtyp angezeigt:
var leftOuterJoinQuery =
from category in categories
join prod in products on category.ID equals prod.CategoryID into prodGroup
from item in prodGroup.DefaultIfEmpty(new Product { Name = String.Empty, CategoryID = 0 })
select new { CatName = category.Name, ProdName = item.Name };
Weitere Informationen finden Sie unter Ausführen von Left Outer Joins.
Der equals-Operator
Eine join
-Klausel führt eine Gleichheitsverknüpfung durch. D.h., dass Übereinstimmungen nur auf der Gleichheit zweier Schlüssel basieren können. Andere Vergleichstypen wie "größer als" oder "nicht gleich" werden nicht unterstützt. Um klarzustellen, dass alle Verknüpfungen equijoins sind, verwendet die join
Klausel das equals
Schlüsselwort anstelle des ==
Operators. Das equals
Schlüsselwort kann nur in einer join
Klausel verwendet werden und unterscheidet sich von dem ==
Operator auf einige wichtige Weise. Beim Vergleichen von Zeichenfolgen equals
weist eine Überladung zum Vergleichen nach Wert auf, und der Operator ==
verwendet die Referenzgleichheit. Wenn beide Vergleichsseiten identische Zeichenfolgenvariablen equals
aufweisen und ==
dasselbe Ergebnis erreichen: true. Das liegt daran, dass der Compiler, wenn ein Programm zwei oder mehr gleichwertige Zeichenfolgenvariablen deklariert, alle an demselben Speicherort speichert. Dies wird als Internierung bezeichnet. Ein weiterer wichtiger Unterschied ist der NULL-Vergleich: null equals null
wird mit dem equals
-Operator als „false“ ausgewertet, mit dem ==
-Operator aber als „true“. Schließlich unterscheidet sich das Geltungsbereichsverhalten: Mit equals
wird die äußere Quellsequenz durch den linken Schlüssel genutzt und die innere Quelle durch den rechten Schlüssel. Die äußere Quelle befindet sich nur im Geltungsbereich auf der linken Seite von equals
und die innere Sequenz befindet sich nur im Geltungsbereich auf der rechten Seite.
Nicht-Gleichheitsverknüpfungen
Sie können Nicht-Equijoins, Kreuzverknüpfungen und andere benutzerdefinierte Verknüpfungsvorgänge ausführen, indem Sie mehrere from
Klauseln verwenden, um neue Sequenzen unabhängig in eine Abfrage einzuführen. Weitere Informationen finden Sie unter Ausführen von benutzerdefinierten Verknüpfungsvorgängen.
Verknüpfungen in Objektsammlungen im Vergleich zu relationalen Tabellen
In einem LINQ-Abfrageausdruck werden Verknüpfungsvorgänge für Objektsammlungen ausgeführt. Objektauflistungen können nicht auf genau die gleiche Weise wie zwei relationale Tabellen "verknüpft" werden. In LINQ sind explizite join
Klauseln nur erforderlich, wenn zwei Quellsequenzen nicht durch eine Beziehung gebunden sind. Beim Arbeiten mit LINQ to SQL werden Fremdschlüsseltabellen im Objektmodell als Eigenschaften der Primärtabelle dargestellt. Beispielsweise weist die Tabelle "Kunde" in der Northwind-Datenbank eine Fremdschlüsselbeziehung mit der Tabelle "Bestellungen" auf. Wenn Sie die Tabellen dem Objektmodell zuordnen, weist die Klasse "Customer" eine Orders-Eigenschaft auf, die die Auflistung von Bestellungen enthält, die diesem Kunden zugeordnet sind. Tatsächlich wurde der Beitritt bereits für Sie erledigt.
Weitere Informationen zum Abfragen verwandter Tabellen im Kontext von LINQ to SQL finden Sie unter How to: Map Database Relationships.
Zusammengesetzte Tasten
Sie können die Gleichheit mehrerer Werte mithilfe eines zusammengesetzten Schlüssels testen. Weitere Informationen finden Sie unter Verknüpfung mithilfe zusammengesetzter Schlüssel. Zusammengesetzte Schlüssel können auch in einer group
Klausel verwendet werden.
Beispiel
Im folgenden Beispiel werden die Ergebnisse einer inneren Verknüpfung, einer Gruppenverknüpfung und einer linken äußeren Verknüpfung an denselben Datenquellen mit denselben Schlüsseln verglichen. Diesen Beispielen werden zusätzlichen Code hinzugefügt, um die Ergebnisse in der Konsolenanzeige zu verdeutlichen.
class JoinDemonstration
{
#region Data
class Product
{
public required string Name { get; init; }
public required int CategoryID { get; init; }
}
class Category
{
public required string Name { get; init; }
public required int ID { get; init; }
}
// Specify the first data source.
List<Category> categories =
[
new Category {Name="Beverages", ID=001},
new Category {Name="Condiments", ID=002},
new Category {Name="Vegetables", ID=003},
new Category {Name="Grains", ID=004},
new Category {Name="Fruit", ID=005}
];
// Specify the second data source.
List<Product> products =
[
new Product {Name="Cola", CategoryID=001},
new Product {Name="Tea", CategoryID=001},
new Product {Name="Mustard", CategoryID=002},
new Product {Name="Pickles", CategoryID=002},
new Product {Name="Carrots", CategoryID=003},
new Product {Name="Bok Choy", CategoryID=003},
new Product {Name="Peaches", CategoryID=005},
new Product {Name="Melons", CategoryID=005},
];
#endregion
static void Main(string[] args)
{
JoinDemonstration app = new JoinDemonstration();
app.InnerJoin();
app.GroupJoin();
app.GroupInnerJoin();
app.GroupJoin3();
app.LeftOuterJoin();
app.LeftOuterJoin2();
}
void InnerJoin()
{
// Create the query that selects
// a property from each element.
var innerJoinQuery =
from category in categories
join prod in products on category.ID equals prod.CategoryID
select new { Category = category.ID, Product = prod.Name };
Console.WriteLine("InnerJoin:");
// Execute the query. Access results
// with a simple foreach statement.
foreach (var item in innerJoinQuery)
{
Console.WriteLine("{0,-10}{1}", item.Product, item.Category);
}
Console.WriteLine($"InnerJoin: {innerJoinQuery.Count()} items in 1 group.");
Console.WriteLine(System.Environment.NewLine);
}
void GroupJoin()
{
// This is a demonstration query to show the output
// of a "raw" group join. A more typical group join
// is shown in the GroupInnerJoin method.
var groupJoinQuery =
from category in categories
join prod in products on category.ID equals prod.CategoryID into prodGroup
select prodGroup;
// Store the count of total items (for demonstration only).
int totalItems = 0;
Console.WriteLine("Simple GroupJoin:");
// A nested foreach statement is required to access group items.
foreach (var prodGrouping in groupJoinQuery)
{
Console.WriteLine("Group:");
foreach (var item in prodGrouping)
{
totalItems++;
Console.WriteLine(" {0,-10}{1}", item.Name, item.CategoryID);
}
}
Console.WriteLine($"Unshaped GroupJoin: {totalItems} items in {groupJoinQuery.Count()} unnamed groups");
Console.WriteLine(System.Environment.NewLine);
}
void GroupInnerJoin()
{
var groupJoinQuery2 =
from category in categories
orderby category.ID
join prod in products on category.ID equals prod.CategoryID into prodGroup
select new
{
Category = category.Name,
Products = from prod2 in prodGroup
orderby prod2.Name
select prod2
};
//Console.WriteLine("GroupInnerJoin:");
int totalItems = 0;
Console.WriteLine("GroupInnerJoin:");
foreach (var productGroup in groupJoinQuery2)
{
Console.WriteLine(productGroup.Category);
foreach (var prodItem in productGroup.Products)
{
totalItems++;
Console.WriteLine(" {0,-10} {1}", prodItem.Name, prodItem.CategoryID);
}
}
Console.WriteLine($"GroupInnerJoin: {totalItems} items in {groupJoinQuery2.Count()} named groups");
Console.WriteLine(System.Environment.NewLine);
}
void GroupJoin3()
{
var groupJoinQuery3 =
from category in categories
join product in products on category.ID equals product.CategoryID into prodGroup
from prod in prodGroup
orderby prod.CategoryID
select new { Category = prod.CategoryID, ProductName = prod.Name };
//Console.WriteLine("GroupInnerJoin:");
int totalItems = 0;
Console.WriteLine("GroupJoin3:");
foreach (var item in groupJoinQuery3)
{
totalItems++;
Console.WriteLine($" {item.ProductName}:{item.Category}");
}
Console.WriteLine($"GroupJoin3: {totalItems} items in 1 group");
Console.WriteLine(System.Environment.NewLine);
}
void LeftOuterJoin()
{
// Create the query.
var leftOuterQuery =
from category in categories
join prod in products on category.ID equals prod.CategoryID into prodGroup
select prodGroup.DefaultIfEmpty(new Product() { Name = "Nothing!", CategoryID = category.ID });
// Store the count of total items (for demonstration only).
int totalItems = 0;
Console.WriteLine("Left Outer Join:");
// A nested foreach statement is required to access group items
foreach (var prodGrouping in leftOuterQuery)
{
Console.WriteLine("Group:");
foreach (var item in prodGrouping)
{
totalItems++;
Console.WriteLine(" {0,-10}{1}", item.Name, item.CategoryID);
}
}
Console.WriteLine($"LeftOuterJoin: {totalItems} items in {leftOuterQuery.Count()} groups");
Console.WriteLine(System.Environment.NewLine);
}
void LeftOuterJoin2()
{
// Create the query.
var leftOuterQuery2 =
from category in categories
join prod in products on category.ID equals prod.CategoryID into prodGroup
from item in prodGroup.DefaultIfEmpty()
select new { Name = item == null ? "Nothing!" : item.Name, CategoryID = category.ID };
Console.WriteLine($"LeftOuterJoin2: {leftOuterQuery2.Count()} items in 1 group");
// Store the count of total items
int totalItems = 0;
Console.WriteLine("Left Outer Join 2:");
// Groups have been flattened.
foreach (var item in leftOuterQuery2)
{
totalItems++;
Console.WriteLine("{0,-10}{1}", item.Name, item.CategoryID);
}
Console.WriteLine($"LeftOuterJoin2: {totalItems} items in 1 group");
}
}
/*Output:
InnerJoin:
Cola 1
Tea 1
Mustard 2
Pickles 2
Carrots 3
Bok Choy 3
Peaches 5
Melons 5
InnerJoin: 8 items in 1 group.
Unshaped GroupJoin:
Group:
Cola 1
Tea 1
Group:
Mustard 2
Pickles 2
Group:
Carrots 3
Bok Choy 3
Group:
Group:
Peaches 5
Melons 5
Unshaped GroupJoin: 8 items in 5 unnamed groups
GroupInnerJoin:
Beverages
Cola 1
Tea 1
Condiments
Mustard 2
Pickles 2
Vegetables
Bok Choy 3
Carrots 3
Grains
Fruit
Melons 5
Peaches 5
GroupInnerJoin: 8 items in 5 named groups
GroupJoin3:
Cola:1
Tea:1
Mustard:2
Pickles:2
Carrots:3
Bok Choy:3
Peaches:5
Melons:5
GroupJoin3: 8 items in 1 group
Left Outer Join:
Group:
Cola 1
Tea 1
Group:
Mustard 2
Pickles 2
Group:
Carrots 3
Bok Choy 3
Group:
Nothing! 4
Group:
Peaches 5
Melons 5
LeftOuterJoin: 9 items in 5 groups
LeftOuterJoin2: 9 items in 1 group
Left Outer Join 2:
Cola 1
Tea 1
Mustard 2
Pickles 2
Carrots 3
Bok Choy 3
Nothing! 4
Peaches 5
Melons 5
LeftOuterJoin2: 9 items in 1 group
Press any key to exit.
*/
Bemerkungen
Eine join
Klausel, die nicht von into
gefolgt wird, wird in einen Join Methodenaufruf übersetzt. Eine join
-Klausel, gefolgt von into
, wird in einen GroupJoin-Methodenaufruf übersetzt.
Siehe auch
- Abfragestichwörter (LINQ)
- Language-Integrated Query (LINQ)
- Verknüpfungsvorgänge
- Gruppenklausel
- Ausführen linker äußerer Verknüpfungen
- Ausführen innerer Verknüpfungen
- Durchführen gruppierter Verknüpfungen
- Sortieren der Ergebnisse einer Verknüpfungsklausel
- Verbinden mithilfe zusammengesetzter Schlüssel
- Kompatible Datenbanksysteme für Visual Studio