This browser is no longer supported.

Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.

Download Microsoft Edge More info about Internet Explorer and Microsoft Edge

The group join is useful for producing hierarchical data structures. It pairs each element from the first collection with a set of correlated elements from the second collection.

For example, a class or a relational database table named Student might contain two fields: Id and Name . A second class or relational database table named Course might contain two fields: StudentId and CourseTitle . A group join of these two data sources, based on matching Student.Id and Course.StudentId , would group each Student with a collection of Course objects (which might be empty).

Each element of the first collection appears in the result set of a group join regardless of whether correlated elements are found in the second collection. In the case where no correlated elements are found, the sequence of correlated elements for that element is empty. The result selector therefore has access to every element of the first collection. This differs from the result selector in a non-group join, which cannot access elements from the first collection that have no match in the second collection.

Warning

Enumerable.GroupJoin has no direct equivalent in traditional relational database terms. However, this method does implement a superset of inner joins and left outer joins. Both of these operations can be written in terms of a grouped join. For more information, see Join Operations and Entity Framework Core, GroupJoin .

The first example in this article shows you how to perform a group join. The second example shows you how to use a group join to create XML elements.

The examples in this topic use the Person and Pet data classes from Perform inner joins .

Example - Group join

The following example performs a group join of objects of type Person and Pet based on the Person matching the Pet.Owner property. Unlike a non-group join, which would produce a pair of elements for each match, the group join produces only one resulting object for each element of the first collection, which in this example is a Person object. The corresponding elements from the second collection, which in this example are Pet objects, are grouped into a collection. Finally, the result selector function creates an anonymous type for each match that consists of Person.FirstName and a collection of Pet objects.

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:

Example - Group join to create XML

Group joins are ideal for creating XML by using LINQ to XML. The following example is similar to the previous example except that instead of creating anonymous types, the result selector function creates XML elements that represent the joined objects.

// 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>

See also

  • GroupJoin
  • Perform inner joins
  • Perform left outer joins
  • Anonymous types
  •