join-Klausel (C#-Referenz)join clause (C# Reference)

Die join-Klausel ist sehr nützlich beim verknüpfen von Elementen aus unterschiedlichen Quellsequenzen, die keine direkte Beziehung im Objektmodell haben.The join clause is useful for associating elements from different source sequences that have no direct relationship in the object model. Die Elemente müssen lediglich in jeder Quelle einige Werte freigeben, die auf Gleichheit verglichen werden können.The only requirement is that the elements in each source share some value that can be compared for equality. Ein Lebensmittelgroßhändler hat z.B. eine Liste seiner Lieferanten und seiner Käufer für ein bestimmtes Produkt.For example, a food distributor might have a list of suppliers of a certain product, and a list of buyers. Eine join-Klausel kann beispielsweise verwendet werden, um eine Liste von Lieferanten und Käufern dieses Produkts zu erstellen, die sich alle in einer angegebenen Region befinden.A join clause can be used, for example, to create a list of the suppliers and buyers of that product who are all in the same specified region.

Eine join-Klausel akzeptiert zwei Quellsequenzen als Eingabe.A join clause takes two source sequences as input. Die Elemente jeder Sequenz müssen entweder eine Eigenschaft sein oder eine Eigenschaft enthalten, die mit einer entsprechenden Eigenschaft einer anderen Sequenz verglichen werden kann.The elements in each sequence must either be or contain a property that can be compared to a corresponding property in the other sequence. Die join-Klausel vergleicht die angegebenen Schlüssel auf Gleichheit, indem sie das besonderen Schlüsselwort equals verwendet.The join clause compares the specified keys for equality by using the special equals keyword. Alle Verknüpfungen, die von der join-Klausel vorgenommen werden, sind Gleichheitsverknüpfungen.All joins performed by the join clause are equijoins. Die Form der Ausgabe einer join-Klausel hängt vom Typ der durchgeführten Verknüpfung ab.The shape of the output of a join clause depends on the specific type of join you are performing. Hier sind die am häufigsten vorkommenden Verknüpfungstypen:The following are three most common join types:

  • Innere VerknüpfungInner join

  • GruppenverknüpfungGroup join

  • Left Outer JoinLeft outer join

Innerer JoinInner Join

Im folgenden Beispiel wird eine einfache Gleichheitsverknüpfung dargestellt.The following example shows a simple inner equijoin. Diese Abfrage produziert eine flache Sequenz aus Paaren der Form „Produktname/Kategorie“.This query produces a flat sequence of "product name / category" pairs. Die gleiche Kategoriezeichenfolge taucht in mehreren Elementen auf.The same category string will appear in multiple elements. Wenn ein Element aus categories keine entsprechenden products hat, wird diese Kategorie nicht in den Ergebnissen angezeigt.If an element from categories has no matching products, that category will not appear in the results.

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 Vorgehensweise: Ausführen innerer Verknüpfungen.For more information, see How to: Perform Inner Joins.

Group JoinGroup Join

Eine join-Klausel mit einem into-Ausdruck wird Gruppenverknüpfung genannt.A join clause with an into expression is called a group join.

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 Gruppenverknüpfung erstellt eine hierarchische Ergebnissequenz, die Elemente in der linken Quellsequenz mit mindestens einem entsprechenden Element der rechten Quellsequenz verknüpft.A group join produces a hierarchical result sequence, which associates elements in the left source sequence with one or more matching elements in the right side source sequence. Eine Gruppenverknüpfung hat keine entsprechenden Beziehungsbedingungen; eigentlich ist sie eine Sequenz von Objektarrays.A group join has no equivalent in relational terms; it is essentially a sequence of object arrays.

Wenn keine Elemente der rechten Quellsequenz gefunden werden, die mit Elementen der linken Sequenz übereinstimmen, erstellt die join-Klausel ein leeres Array für dieses Element.If no elements from the right source sequence are found to match an element in the left source, the join clause will produce an empty array for that item. Deshalb ist eine Gruppenverknüpfung immer noch grundsätzlich eine innere Gleichheitsverknüpfung, nur dass die Ergebnissequenz in Gruppen aufgeteilt ist.Therefore, the group join is still basically an inner-equijoin except that the result sequence is organized into groups.

Wenn Sie nur das Ergebnis einer Gruppenverknüpfung auswählen, können Sie auf Elemente zugreifen, aber Sie können nicht den Schlüssel identifizieren, der ihnen gleich ist.If you just select the results of a group join, you can access the items, but you cannot identify the key that they match on. 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.Therefore, it is generally more useful to select the results of the group join into a new type that also has the key name, as shown in the previous example.

Selbstverständlich können Sie auch das Ergebnis einer Gruppenverknüpfung als Generator einer anderen Unterabfrage verwenden:You can also, of course, use the result of a group join as the generator of another subquery:

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 Vorgehensweise: Ausführen von Gruppenverknüpfungen.For more information, see How to: Perform Grouped Joins.

Linker äußerer JoinLeft Outer Join

In einem Left Outer Join werden alle Elemente der linken Quellsequenz zurückgegeben, auch wenn sich keine entsprechenden Elemente in der rechten Sequenz befinden.In a left outer join, all the elements in the left source sequence are returned, even if no matching elements are in the right sequence. Um einen Left Outer Join in LINQLINQ durchzuführen, verwenden Sie die Methode DefaultIfEmpty zusammen mit einer Gruppenverknüpfung, um ein Standardelement für den rechten Bereich festzulegen, das erstellt wird, wenn es kein entsprechendes Element im linken Bereich gibt.To perform a left outer join in LINQLINQ, use the DefaultIfEmpty method in combination with a group join to specify a default right-side element to produce if a left-side element has no matches. Sie können null als Standardwert für jeden beliebigen Verweistyp verwenden, oder Sie können einen benutzerdefinierten Standardtyp festlegen.You can use null as the default value for any reference type, or you can specify a user-defined default type. Im folgendem Beispiel wird ein benutzerdefinierter Standardtyp dargestellt:In the following example, a user-defined default type is shown:

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 Vorgehensweise: Ausführen linker äußerer Verknüpfungen.For more information, see How to: Perform Left Outer Joins.

Der equals-OperatorThe equals operator

Eine join-Klausel führt eine Gleichheitsverknüpfung durch.A join clause performs an equijoin. D.h., dass Übereinstimmungen nur auf der Gleichheit zweier Schlüssel basieren können.In other words, you can only base matches on the equality of two keys. Andere Vergleichstypen wie etwa „größer als“ oder „ungleich“ werden nicht unterstützt.Other types of comparisons such as "greater than" or "not equals" are not supported. Um sicherzustellen, dass die Verknüpfungen Gleichheitsverknüpfungen sind, verwendet die join-Klausel das Schlüsselwort equals statt des Operators ==.To make clear that all joins are equijoins, the join clause uses the equals keyword instead of the == operator. Das Schlüsselwort equals kann nur in einer join-Klausel verwendet werden, und es unterscheidet sich vom Operator == in einem wesentlichen Punkt.The equals keyword can only be used in a join clause and it differs from the == operator in one important way. Der linke Schlüssel verarbeitet mit equals die äußere Quellsequenz, und der rechte Schlüssel verarbeitet die innere Quelle.With equals, the left key consumes the outer source sequence, and the right key consumes the inner source. Die äußere Quelle befindet sich nur links von equals im Geltungsbereich, und die innere Quellsequenz befindet sich nur auf der rechten Seite im Geltungsbereich.The outer source is only in scope on the left side of equals and the inner source sequence is only in scope on the right side.

Nicht-GleichheitsverknüpfungenNon-Equijoins

Sie können Nicht-Gleichheitsverknüpfungen, Kreuzverknüpfungen und andere benutzerdefinierte Verknüpfungen durchführen, indem Sie mehrere from-Klauseln verwenden, um unabhängig neue Sequenzen in eine Abfrage einzuführen.You can perform non-equijoins, cross joins, and other custom join operations by using multiple from clauses to introduce new sequences independently into a query. Weitere Informationen finden Sie unter Vorgehensweise: Ausführen von benutzerdefinierten Verknüpfungsoperationen.For more information, see How to: Perform Custom Join Operations.

Verknüpfungen für Objektauflistungen vs. relationale TabellenJoins on object collections vs. relational tables

Verknüpfungsvorgänge in einem LINQLINQ-Abfrageausdruck werden in Objektauflistungen durchgeführt.In a LINQLINQ query expression, join operations are performed on object collections. Objektauflistungen können nicht wie relationale Tabellen „verknüpft“ werden.Object collections cannot be "joined" in exactly the same way as two relational tables. In LINQLINQ sind explizite join-Klauseln nur erforderlich, wenn zwei Quellsequenzen nicht durch eine Beziehung verbunden sind.In LINQLINQ, explicit join clauses are only required when two source sequences are not tied by any relationship. Wenn Sie mit LINQ to SQLLINQ to SQL arbeiten, werden Tabellen mit Fremdschlüsseln in einem Objektmodell als Eigenschaften der primären Tabelle repräsentiert.When working with LINQ to SQLLINQ to SQL, foreign key tables are represented in the object model as properties of the primary table. In der Northwind-Datenbank weist die Tabelle „Customers“ (Kunden) beispielsweise eine Fremdschlüsselbeziehung zu der Tabelle „Orders“ (Aufträge) auf.For example, in the Northwind database, the Customer table has a foreign key relationship with the Orders table. Wenn Sie die Tabellen dem Objektmodell zuordnen, hat die Klasse „Customers“ eine Eigenschaft „Orders“, die die Auflistung der Aufträge enthält, die zu diesem Kunden gehören.When you map the tables to the object model, the Customer class has an Orders property that contains the collection of Orders associated with that Customer. Tatsächlich wurde die Verknüpfung bereits für Sie vorgenommen.In effect, the join has already been done for you.

Weitere Informationen zu Abfragen über verknüpfte Quellen hinweg in Bezug auf LINQ to SQLLINQ to SQL finden Sie unter Vorgehensweise: Zuordnen von Datenbankbeziehungen.For more information about querying across related tables in the context of LINQ to SQLLINQ to SQL, see How to: Map Database Relationships.

Zusammengesetzte SchlüsselComposite Keys

Mithilfe eines zusammengesetzten Schlüssels können Sie auf die Gleichheit mehrerer Werte prüfen.You can test for equality of multiple values by using a composite key. Weitere Informationen finden Sie unter Vorgehensweise: Verknüpfen mithilfe eines zusammengesetzten Schlüssels.For more information, see How to: Join by Using Composite Keys. Zusammengesetzte Schlüssel können auch in einer group-Klausel verwendet werden.Composite keys can be also used in a group clause.

BeispielExample

In folgendem Beispiel werden die Ergebnisse einer inneren Verknüpfung, einer Gruppenverknüpfung und einer linken äußeren Verknüpfung in der gleichen Datenquelle anhand derselben übereinstimmenden Schlüssel miteinander verglichen.The following example compares the results of an inner join, a group join, and a left outer join on the same data sources by using the same matching keys. Diesen Beispielen wurde zusätzlicher Code hinzugefügt, um die Ergebnisse in der Konsolenanzeige zu verdeutlichen.Some extra code is added to these examples to clarify the results in the console display.

class JoinDemonstration
{
    #region Data

    class Product
    {
        public string Name { get; set; }
        public int CategoryID { get; set; }
    }

    class Category
    {
        public string Name { get; set; }
        public int ID { get; set; }
    }

    // Specify the first data source.
    List<Category> categories = new List<Category>()
    { 
        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 List<Product>()
   {
      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();

        // Keep the console window open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }

    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: {0} items in 1 group.", innerJoinQuery.Count());
        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: {0} items in {1} unnamed groups", totalItems, groupJoinQuery.Count());
        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: {0} items in {1} named groups", totalItems, groupJoinQuery2.Count());
        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("   {0}:{1}", item.ProductName, item.Category);
        }

        Console.WriteLine("GroupJoin3: {0} items in 1 group", totalItems, groupJoinQuery3.Count());
        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:", prodGrouping.Count());
            foreach (var item in prodGrouping)
            {
                totalItems++;
                Console.WriteLine("  {0,-10}{1}", item.Name, item.CategoryID);
            }
        }
        Console.WriteLine("LeftOuterJoin: {0} items in {1} groups", totalItems, leftOuterQuery.Count());
        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: {0} items in 1 group", leftOuterQuery2.Count());
        // 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: {0} items in 1 group", totalItems);
    }
}
/*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.
*/

HinweiseRemarks

Eine join-Klausel, auf die kein into folgt, wird in einen Join-Methodenaufruf übersetzt.A join clause that is not followed by into is translated into a Join method call. Eine join-Klausel, auf die into folgt, wird in einen GroupJoin-Methodenaufruf übersetzt.A join clause that is followed by into is translated to a GroupJoin method call.

Siehe auchSee Also

Abfrageschlüsselwörter (LINQ)Query Keywords (LINQ)
LINQ-AbfrageausdrückeLINQ Query Expressions
VerknüpfungsvorgängeJoin Operations
group-Klauselgroup clause
Gewusst wie: Ausführen linker äußerer VerknüpfungenHow to: Perform Left Outer Joins
Gewusst wie: Ausführen innerer VerknüpfungenHow to: Perform Inner Joins
Gewusst wie: Ausführen von GruppenverknüpfungenHow to: Perform Grouped Joins
Gewusst wie: Sortieren der Ergebnisse einer Join-KlauselHow to: Order the Results of a Join Clause
Gewusst wie: Verknüpfen mithilfe eines zusammengesetzten SchlüsselsHow to: Join by Using Composite Keys
Gewusst wie: Installieren von BeispieldatenbankenHow to: Install Sample Databases