How to: Perform Grouped Joins (C# Programming Guide)

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).

Note

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.

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

Example

Group Join Example

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.

class Person
        {
            public string FirstName { get; set; }
            public string LastName { get; set; }
        }

        class Pet
        {
            public string Name { get; set; }
            public Person Owner { get; set; }
        }

        /// <summary> 
        /// This example performs a grouped join. 
        /// </summary> 
        public static void GroupJoinExample()
        {
            Person magnus = new Person { FirstName = "Magnus", LastName = "Hedlund" };
            Person terry = new Person { FirstName = "Terry", LastName = "Adams" };
            Person charlotte = new Person { FirstName = "Charlotte", LastName = "Weiss" };
            Person arlene = new Person { FirstName = "Arlene", LastName = "Huff" };

            Pet barley = new Pet { Name = "Barley", Owner = terry };
            Pet boots = new Pet { Name = "Boots", Owner = terry };
            Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte };
            Pet bluemoon = new Pet { Name = "Blue Moon", Owner = terry };
            Pet daisy = new Pet { Name = "Daisy", Owner = magnus };

            // Create two lists.
            List<Person> people = new List<Person> { magnus, terry, charlotte, arlene };
            List<Pet> pets = new List<Pet> { barley, boots, whiskers, bluemoon, daisy };

            // 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("{0}:", v.OwnerName);
                // Output each of the owner's pet's names. 
                foreach (Pet pet in v.Pets)
                    Console.WriteLine("  {0}", pet.Name);
            }
        }

        // This code produces the following output: 
        // 
        // Magnus: 
        //   Daisy 
        // Terry: 
        //   Barley 
        //   Boots 
        //   Blue Moon 
        // Charlotte: 
        //   Whiskers 
        // Arlene:

Group Join to Create XML Example

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. For more information about LINQ to XML, see LINQ to XML.

class Person
        {
            public string FirstName { get; set; }
            public string LastName { get; set; }
        }

        class Pet
        {
            public string Name { get; set; }
            public Person Owner { get; set; }
        }

        /// <summary> 
        /// This example creates XML output from a grouped join. 
        /// </summary> 
        public static void GroupJoinXMLExample()
        {
            Person magnus = new Person { FirstName = "Magnus", LastName = "Hedlund" };
            Person terry = new Person { FirstName = "Terry", LastName = "Adams" };
            Person charlotte = new Person { FirstName = "Charlotte", LastName = "Weiss" };
            Person arlene = new Person { FirstName = "Arlene", LastName = "Huff" };

            Pet barley = new Pet { Name = "Barley", Owner = terry };
            Pet boots = new Pet { Name = "Boots", Owner = terry };
            Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte };
            Pet bluemoon = new Pet { Name = "Blue Moon", Owner = terry };
            Pet daisy = new Pet { Name = "Daisy", Owner = magnus };

            // Create two lists.
            List<Person> people = new List<Person> { magnus, terry, charlotte, arlene };
            List<Pet> pets = new List<Pet> { barley, boots, whiskers, bluemoon, daisy };

            // Create XML to display the hierarchical organization of people and their pets.
            XElement ownersAndPets = new XElement("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);
        }

        // This code produces the following 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>

Compiling the Code

  • Create a new Console Application project in Visual Studio.

  • Add a reference to System.Core.dll and to System.Xml.Linq.dll if they are not already referenced.

  • Include the System.Linq and System.Xml.Linq namespaces.

  • Copy and paste the code from the example into the program.cs file, below the Main method. Add a line of code to the Main method to call the method you pasted in.

  • Run the program.

See Also

Tasks

How to: Perform Inner Joins (C# Programming Guide)

How to: Perform Left Outer Joins (C# Programming Guide)

Reference

Join

GroupJoin

Anonymous Types (C# Programming Guide)

Concepts

Join Operations

Anonymous Types (Visual Basic)

Other Resources

LINQ to XML