グループ結合の実行

グループ結合は、階層データ構造を作成する場合に便利です。 これは、最初のコレクションの各要素と、2 番目のコレクションの相関関係を持つ要素のセットを組み合わせたものです。

たとえば、Student という名前のクラスまたはリレーショナル データベース テーブルに、IdName という 2 つのフィールドが含まれているとします。 Course という名前の 2 番目のクラスまたはリレーショナル データベース テーブルには、StudentIdCourseTitle という 2 つのフィールドが含まれているとします。 この 2 つのデータ ソースのグループ結合は、Student.IdCourse.StudentId の一致に基づいて、Course オブジェクトのコレクションを持つ各 Student をグループ化します (コレクションは空の場合もあります)。

注意

最初のコレクションの各要素は、2 番目のコレクションに相関関係を持つ要素があるかどうかにかかわらず、グループ結合の結果セットに表示されます。 相関関係を持つ要素が見つからない場合、その要素の相関関係を持つ要素のシーケンスは空です。 そのため、結果セレクターは最初のコレクションのすべての要素にアクセスできます。 これは、非グループ結合の結果セレクターとは異なります。非グループ結合の結果セレクターは、2 番目のコレクションに一致するものがない最初のコレクションの要素にアクセスすることはできません。

警告

Enumerable.GroupJoin には、従来のリレーショナル データベースの用語に直接相当するものはありません。 ただし、このメソッドでは内部結合と左外部結合のスーパーセットが実装されます。 これらの操作はどちらも、グループ化結合の観点から記述できます。 詳細については、「結合操作」と「Entity Framework Core」の「GroupJoin」を参照してください。

この記事の最初の例では、グループ結合を実行する方法を示します。 2 つ目の例では、グループ結合を使用して XML 要素を作成する方法を示します。

注意

このトピックの例では、「内部結合の実行」からの Person および Pet データ クラスを使用します。

例 - グループ結合

次の例では、Pet.Owner プロパティと一致する Person に基づいて、Person 型と Pet 型のオブジェクトのグループ結合を実行します。 一致ごとに要素のペアを生成する非グループ結合と異なり、グループ結合は最初のコレクションの要素ごとに 1 つのオブジェクト (この例では Person オブジェクト) のみを作成します。 2 番目のコレクションの対応する要素 (この例では Pet オブジェクト) が 1 つのコレクションにグループ化されます。 最後に、結果セレクター機能により、Person.FirstName と、Pet オブジェクトのコレクションで構成される一致ごとに匿名型が作成されます。

Person magnus = new(FirstName: "Magnus", LastName: "Hedlund");
Person terry = new("Terry", "Adams");
Person charlotte = new("Charlotte", "Weiss");
Person arlene = new("Arlene", "Huff");

List<Person> people = new() { magnus, terry, charlotte, arlene };

List<Pet> pets = new()
{
    new(Name: "Barley", Owner: terry),
    new("Boots", terry),
    new("Whiskers", charlotte),
    new("Blue Moon", terry),
    new("Daisy", magnus),
};

// Create a list where each element is an anonymous type
// that contains the person's first name and a collection of
// pets that are owned by them.
var query =
    from person in people
    join pet in pets on person equals pet.Owner into gj
    select new
    {
        OwnerName = person.FirstName,
        Pets = gj
    };

foreach (var v in query)
{
    // Output the owner's name.
    Console.WriteLine($"{v.OwnerName}:");

    // Output each of the owner's pet's names.
    foreach (var pet in v.Pets)
    {
        Console.WriteLine($"  {pet.Name}");
    }
}

/* Output:
     Magnus:
       Daisy
     Terry:
       Barley
       Boots
       Blue Moon
     Charlotte:
       Whiskers
     Arlene:
 */

例 - XML を作成するグループ結合

グループ結合は、LINQ to XML を使用した XML の作成に適しています。 次の例は前の例に似ていますが、匿名型を作成するのではなく、結果セレクター機能により、結合されたオブジェクトを表す XML 要素を作成する点が異なります。

// using System.Xml.Linq;

Person magnus = new(FirstName: "Magnus", LastName: "Hedlund");
Person terry = new("Terry", "Adams");
Person charlotte = new("Charlotte", "Weiss");
Person arlene = new("Arlene", "Huff");

List<Person> people = new() { magnus, terry, charlotte, arlene };

List<Pet> pets = new()
{
    new(Name: "Barley", Owner: terry),
    new("Boots", terry),
    new("Whiskers", charlotte),
    new("Blue Moon", terry),
    new("Daisy", magnus),
};

XElement ownersAndPets = new("PetOwners",
    from person in people
    join pet in pets on person equals pet.Owner into gj
    select new XElement("Person",
        new XAttribute("FirstName", person.FirstName),
        new XAttribute("LastName", person.LastName),
        from subpet in gj
        select new XElement("Pet", subpet.Name)
    )
);

Console.WriteLine(ownersAndPets);

/* Output:
     <PetOwners>
       <Person FirstName="Magnus" LastName="Hedlund">
         <Pet>Daisy</Pet>
       </Person>
       <Person FirstName="Terry" LastName="Adams">
         <Pet>Barley</Pet>
         <Pet>Boots</Pet>
         <Pet>Blue Moon</Pet>
       </Person>
       <Person FirstName="Charlotte" LastName="Weiss">
         <Pet>Whiskers</Pet>
       </Person>
       <Person FirstName="Arlene" LastName="Huff" />
     </PetOwners>
*/

関連項目