Klauzula join (odwołanie w C#)join clause (C# Reference)

join Klauzuli przydaje się do kojarzenia elementów z sekwencji innego źródła, które nie mają bezpośredniego relacji w modelu obiektów.The join clause is useful for associating elements from different source sequences that have no direct relationship in the object model. Jedynym wymaganiem jest, że elementy w każdym źródle udostępniać niektóre wartości, które mogą być porównywane pod kątem równości.The only requirement is that the elements in each source share some value that can be compared for equality. Na przykład dystrybutora żywności może mieć listy dostawców określonego produktu oraz listę kupujący.For example, a food distributor might have a list of suppliers of a certain product, and a list of buyers. A join klauzuli może służyć, na przykład, aby utworzyć listę dostawców i kupujący tego produktu, którzy są w taki sam określony region.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.

A join klauzuli przyjmuje dwóch źródłowych sekwencji jako dane wejściowe.A join clause takes two source sequences as input. Elementów w każdej sekwencji musi być albo zawiera właściwości, które można porównać do odpowiadającą właściwość w innych sekwencji.The elements in each sequence must either be or contain a property that can be compared to a corresponding property in the other sequence. join Klauzuli porównuje klucze określonego pod kątem równości przy użyciu specjalnych equals — słowo kluczowe.The join clause compares the specified keys for equality by using the special equals keyword. Wszystkie sprzężenia, wykonywane przez join klauzuli są equijoins.All joins performed by the join clause are equijoins. Kształt danych wyjściowych join klauzuli zależy od określonego typu sprzężenia wykonywana.The shape of the output of a join clause depends on the specific type of join you are performing. Poniżej przedstawiono trzy najbardziej powszechne typy join:The following are three most common join types:

  • Sprzężenie wewnętrzneInner join

  • Łączenie grupoweGroup join

  • Lewe sprzężenie zewnętrzneLeft outer join

Sprzężenie wewnętrzneInner join

Poniższy przykład pokazuje prosty equijoin wewnętrznego.The following example shows a simple inner equijoin. To zapytanie tworzy prostych sekwencji "Nazwa produktu / category" pary.This query produces a flat sequence of "product name / category" pairs. Ten sam ciąg kategorii będą wyświetlane w wielu elementów.The same category string will appear in multiple elements. Jeśli element z categories nie ma odpowiadającego products, tej kategorii będą widoczne w wynikach.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

Aby uzyskać więcej informacji, zobacz wykonanie sprzężeń wewnętrznych.For more information, see Perform inner joins.

Łączenie grupoweGroup join

A join klauzula into wyrażenie jest wywoływane sprzężenie grupy.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 };

Sprzężenie grupy tworzy sekwencję wyniku hierarchicznego, który kojarzy elementów w sekwencji źródłowej po lewej stronie z co najmniej jeden zgodnych elementów w sekwencji źródłowej po prawej stronie.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. Sprzężenie grupy nie ma odpowiednika w relacyjnego kategoriach; jest zasadniczo sekwencję tablic obiektów.A group join has no equivalent in relational terms; it is essentially a sequence of object arrays.

Jeśli odpowiadający element w źródle po lewej stronie znajdują się żadnych elementów z sekwencji źródłowej prawo join klauzuli dadzą pustą tablicę dla tego elementu.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. Dlatego sprzężenie grupy jest nadal zasadniczo sprzężenie wewnętrzne różnicą, że kolejność wyniku są zorganizowane w grupy.Therefore, the group join is still basically an inner-equijoin except that the result sequence is organized into groups.

Wybranie tylko wyniki sprzężenie grupy uzyskują dostęp do elementów, ale nie może zidentyfikować są zgodne na klucz.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. Dlatego jest zazwyczaj bardziej użyteczna, wybrać wyniki sprzężenie grupy do nowego typu, który ma również nazwę klucza, jak pokazano w poprzednim przykładzie.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.

Oczywiście, umożliwia również wynikiem sprzężenia grupy jako generator innego podzapytania: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;

Aby uzyskać więcej informacji, zobacz wykonaj pogrupowane sprzężeń.For more information, see Perform grouped joins.

Lewe sprzężenie zewnętrzneLeft outer join

Lewego sprzężenia zewnętrznego wszystkie elementy w sekwencji źródłowej po lewej stronie zostaną zwrócone, nawet jeśli w prawej sekwencji żadnych zgodnych elementów.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. Aby wykonać lewe sprzężenie zewnętrzne w LINQLINQ, użyj DefaultIfEmpty metody w połączeniu z sprzężenie grupy, aby określić domyślny element po prawej stronie, do produkcji, jeśli element po lewej stronie nie ma żadnych dopasowań.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. Możesz użyć null jako wartość domyślna w przypadku dowolnego odwołania do typu, lub można określić typ domyślny zdefiniowanych przez użytkownika.You can use null as the default value for any reference type, or you can specify a user-defined default type. W poniższym przykładzie pokazano zdefiniowane przez użytkownika domyślny typ: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 };

Aby uzyskać więcej informacji, zobacz wykonaj Lewe sprzężenia zewnętrzne.For more information, see Perform left outer joins.

Operator równościThe equals operator

A join klauzuli wykonuje sprzężenie.A join clause performs an equijoin. Innymi słowy możesz to zrobić tylko podstawowy dopasowań na równość dwa klucze.In other words, you can only base matches on the equality of two keys. Innych rodzajów porównań, takie jak "większe niż" lub "nie równa się" nie są obsługiwane.Other types of comparisons such as "greater than" or "not equals" are not supported. Aby wyjaśnić, czy wszystkie sprzężeń equijoins, join używa klauzuli equals słowa kluczowego zamiast == operatora.To make clear that all joins are equijoins, the join clause uses the equals keyword instead of the == operator. equals — Słowo kluczowe można używać tylko w join klauzuli i różni się od == operatora w jednym ze sposobów ważne.The equals keyword can only be used in a join clause and it differs from the == operator in one important way. Za pomocą equalsStrzałka w lewo zużywa sekwencji źródło zewnętrzne i Strzałka w prawo zużywa typu inner source.With equals, the left key consumes the outer source sequence, and the right key consumes the inner source. Źródło zewnętrzne jest tylko do zakresu po lewej stronie equals i sekwencji źródłowej wewnętrzny jest tylko w zakresie po prawej stronie.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.

Non-equijoinsNon-equijoins

Można wykonać innych niż equijoins, sprzężeń i innych niestandardowych operacji łączenia za pomocą wielu from klauzul, aby wprowadzić nowy sekwencje niezależnie do zapytania.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. Aby uzyskać więcej informacji, zobacz wykonywanie niestandardowych operacji łączenia.For more information, see Perform custom join operations.

Sprzężenia w kolekcji obiektów w porównaniu z tabelami relacyjnymiJoins on object collections vs. relational tables

W LINQLINQ wyrażenie zapytania, sprzężenia operacje są wykonywane w kolekcji obiektów.In a LINQLINQ query expression, join operations are performed on object collections. Obiekt kolekcji nie może być "łączone" w taki sam sposób, jak dwie tabele relacyjne.Object collections cannot be "joined" in exactly the same way as two relational tables. W LINQLINQ, jawna join klauzule są tylko wymagane w przypadku dwóch źródłowych sekwencji nie są powiązane przez żadnych relacji.In LINQLINQ, explicit join clauses are only required when two source sequences are not tied by any relationship. Podczas pracy z LINQ do SQLLINQ to SQL, tabel kluczy obcych są reprezentowane w modelu obiektu jako właściwości tabeli podstawowej.When working with LINQ do SQLLINQ to SQL, foreign key tables are represented in the object model as properties of the primary table. Na przykład w bazie danych Northwind tabeli klientów ma relacji klucza obcego z tabeli zamówienia.For example, in the Northwind database, the Customer table has a foreign key relationship with the Orders table. Kiedy mapujesz tabele do modelu obiektu klasy klienta ma właściwość zamówienia, który zawiera kolekcję zleceń skojarzonych z tym klientem.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. W efekcie sprzężenia już przeprowadzono dla Ciebie.In effect, the join has already been done for you.

Aby uzyskać więcej informacji na temat wykonywania zapytań w tabelach pokrewnych w kontekście LINQ do SQLLINQ to SQL, zobacz jak: Mapowanie relacji w bazie danych.For more information about querying across related tables in the context of LINQ do SQLLINQ to SQL, see How to: Map Database Relationships.

Klucze złożoneComposite keys

Możesz przetestować pod kątem równości wielu wartości przy użyciu klucza złożonego.You can test for equality of multiple values by using a composite key. Aby uzyskać więcej informacji, zobacz sprzęganie za pomocą kluczy złożonych.For more information, see Join by using composite keys. Klucze złożone, które mogą być również używane w group klauzuli.Composite keys can be also used in a group clause.

PrzykładExample

W poniższym przykładzie porównano wynikiem sprzężenia wewnętrznego, łączenie grupy i lewe sprzężenie zewnętrzne na te same źródła danych przy użyciu tych samych kluczy dopasowania.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. Dodatkowy kod jest dodawany do tych przykładów, aby wyjaśnić, wyniki w oknie konsoli.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);
           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: {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.
   */

UwagiRemarks

A join klauzula, która nie jest zakończony znakiem into jest tłumaczony na Join wywołania metody.A join clause that is not followed by into is translated into a Join method call. A join klauzula, która następuje into jest tłumaczony GroupJoin wywołania metody.A join clause that is followed by into is translated to a GroupJoin method call.

Zobacz takżeSee also