グループ結合の実行
グループ結合は、階層データ構造を作成する場合に便利です。 これは、最初のコレクションの各要素と、2 番目のコレクションの相関関係を持つ要素のセットを組み合わせたものです。
たとえば、Student
という名前のクラスまたはリレーショナル データベース テーブルに、Id
と Name
という 2 つのフィールドが含まれているとします。 Course
という名前の 2 番目のクラスまたはリレーショナル データベース テーブルには、StudentId
と CourseTitle
という 2 つのフィールドが含まれているとします。 この 2 つのデータ ソースのグループ結合は、Student.Id
と Course.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>
*/