LINQ Group Join in C#

LINQ Group Join in C# using both Method and Query Syntax

In this article, I am going to discuss LINQ Group Join in C# using both Method and Query Syntax with Examples. Please read our previous article where we discussed How to Join Multiple Data Sources in LINQ with Examples.

What is LINQ Group Join?

In LINQ, we can apply the Group Join on two or more data sources based on a common key (the key must exist in both the data sources) like the Inner Join, and then LINQ Group Join produces the result set in the form of groups. In simple words, we can say that LINQ Group Join is used to group the result sets based on a common key.

So, the Group Join is basically used to produce hierarchical data structures. Each item from the first data source is paired with a set of correlated items from the second data source. There are two overloaded versions of this GroupJoin method available in LINQ. They are as follows.

What is LINQ Group Join?

The one and only difference between the above two overloaded versions is that the second overloaded version takes an additional IEqualityComparer as an extra parameter. So, while working with Linq Group Join, we need to understand the following five things.

  1. Outer Data Source
  2. Inner Data Source
  3. Outer Key Selector
  4. Inner Key Selector
  5. Result Selector
Examples to Understand LINQ Group Join in C#:

Let us understand How to Implement LINQ Group Join with examples using C# language. For this, we are going to use the following two model classes i.e. Employee and Department. So, create a class file with the name Employee.cs and then copy and paste the following code into it. This is a very simple class having 3 properties i.e. Id, Name, and DepartmentId. We have also created one method which is going to return a collection of Employees which is going to be our first data source going to be used in the Group Join.

using System.Collections.Generic;
namespace LINQGroupJoin
{
    public class Employee
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public int DepartmentId { get; set; }

        public static List<Employee> GetAllEmployees()
        {
            return new List<Employee>()
            {
                new Employee { ID = 1, Name = "Preety", DepartmentId = 10},
                new Employee { ID = 2, Name = "Priyanka", DepartmentId =20},
                new Employee { ID = 3, Name = "Anurag", DepartmentId = 30},
                new Employee { ID = 4, Name = "Pranaya", DepartmentId = 30},
                new Employee { ID = 5, Name = "Hina", DepartmentId = 20},
                new Employee { ID = 6, Name = "Sambit", DepartmentId = 10},
                new Employee { ID = 7, Name = "Happy", DepartmentId = 10},
                new Employee { ID = 8, Name = "Tarun", DepartmentId = 0},
                new Employee { ID = 9, Name = "Santosh", DepartmentId = 10},
                new Employee { ID = 10, Name = "Raja", DepartmentId = 20},
                new Employee { ID = 11, Name = "Ramesh", DepartmentId = 30}
            };
        }
    } 
}

Next, create another class file with the name Department.cs and then copy and paste the following code into it. This is a very simple class having 2 properties i.e. Id, and Name. We have also created one method which is going to return a collection of departments which is going to be our second data source going to be used in the Group Join.

using System.Collections.Generic;
namespace LINQGroupJoin
{
    public class Department
    {
        public int ID { get; set; }
        public string Name { get; set; }

        public static List<Department> GetAllDepartments()
        {
            return new List<Department>()
            {
                new Department { ID = 10, Name = "IT"},
                new Department { ID = 20, Name = "HR"},
                new Department { ID = 30, Name = "Sales"  },
            };
        }
    }
}

As you can see we created the above Employee and Department classes with some simple properties. The common property is Department ID i.e. the ID property in the Department class and DepartmentID property in the Employee class. Then we create two simple methods that are going to return the respective data sources. Further, if you notice the employee with ID 8 does not have a department.

Example to Understand LINQ GroupJoin Method Using Method Syntax in C#

Now, our business requirement is to group the employees by department. So, the outer data source is going to be the department data source and the inner data source is going to be the employee data source. To group the employees by department we need to use the LINQ GroupJoin method. The following code snippet shows how to group the employees by department using LINQ GroupJoin Method using Method Syntax.

Example to Understand LINQ GroupJoin Method Using Method Syntax

As you can see in the above code snippet, our Outer Data Source is Department’s collection and our Inner Data Source is Employee’s collection. Here, we are accessing the Department collection using the dept variable and the Employees collection using the emp variable. Here, the Outer Key Selector is the ID property of the Department class and the Inner Key Selector is the DepartmentId property of the Employee class. Finally, we are projecting the dept and emp to an Anonymous type. The complete example code is given below. The following example code is self-explained, so please go through the comment lines.

using System.Linq;
using System;

namespace LINQGroupJoin
{
    class Program
    {
        static void Main(string[] args)
        {
            //Group Employees by Department using Method Syntax
            var GroupJoinMS = Department.GetAllDepartments(). //Outer Data Source i.e. Departments
                GroupJoin( //Performing Group Join with Inner Data Source
                    Employee.GetAllEmployees(), //Inner Data Source
                    dept => dept.ID, //Outer Key Selector  i.e. the Common Property
                    emp => emp.DepartmentId, //Inner Key Selector  i.e. the Common Property
                    (dept, emp) => new { dept, emp } //Projecting the Result to an Anonymous Type
                );

            //Printing the Result set
            //Outer Foreach is for Each department
            foreach (var item in GroupJoinMS)
            {
                Console.WriteLine("Department :" + item.dept.Name);
                //Inner Foreach loop for each employee of a Particular department
                foreach (var employee in item.emp)
                {
                    Console.WriteLine("  EmployeeID : " + employee.ID + " , Name : " + employee.Name);
                }
            }

            Console.ReadLine();
        }
    }
}
Output:

Example to Understand LINQ GroupJoin Method Using Method Syntax in C#

As you can see the employee with id 8 does not display here. This is because the employee with id 8 does not belong to any department.

Example to Understand LINQ GroupJoin Using Query Syntax in C#

In LINQ Query Syntax there is no such Group Join operator is available. Here we need to use the LINQ Inner Join along with the “into” operator. For a better understanding, please have a look at the following code snippet. Here, we have divided the code snippet into three sections for a better understanding. In the first section, we are simply performing the LINQ Inner Join Operation between the Department and Employee Data Sources. In the second section, we are projecting the result of the Inner Join into a variable called EmployeeGroups using the “into” operator. And in the final section, we are projecting the final result set as dept and EmployeeGroups. That is, it will group employees by department.

Example to Understand LINQ GroupJoin Using Query Syntax in C#

The complete example code is given below. The following example code is self-explained, so please go through the comment lines. Here, we are using LINQ Query Syntax to implement Group Join.

using System.Linq;
using System;
namespace LINQGroupJoin
{
    class Program
    {
        static void Main(string[] args)
        {
            //Group Employees by Department using Query Syntax
            var GroupJoinQS = from dept in Department.GetAllDepartments() //Outer Data Source i.e. Departments
                              join emp in Employee.GetAllEmployees() //Joining with Inner Data Source i.e. Employees
                              on dept.ID equals emp.DepartmentId //Joining Condition

                              into EmployeeGroups //Projecting the Joining Result into EmployeeGroups

                              //Final Result include each department and the corresponding employees
                              select new { dept, EmployeeGroups };

            //Printing the Result set
            //Outer Foreach is for Each department
            foreach (var item in GroupJoinQS)
            {
                Console.WriteLine("Department :" + item.dept.Name);
                //Inner Foreach loop for each employee of a Particular department
                foreach (var employee in item.EmployeeGroups)
                {
                    Console.WriteLine("  EmployeeID : " + employee.ID + " , Name : " + employee.Name);
                }
            }
            
            Console.ReadLine();
        }
    }
}

Run the application and it will also print the same output as the previous example as shown in the below image. Here, you can see the employee with id 8 does not display here. This is because the employee with id 8 does not belong to any department.

Example to Understand LINQ GroupJoin Using Query Syntax in C#

Projecting the Result to a Named Type:

So far the examples we have discussed, we have projected the result to an anonymous type, Can we Project the Result to a Named type? Yes, it is also possible to project the result to a named type instead of an anonymous type.  Let us see how we can do this. First, create a class file with the name GroupEmployeeByDepartment.cs with the required properties that you want in the result set. As per our requirement, we have created the class with the following two properties.

using System.Collections.Generic;
namespace LINQGroupJoin
{
    class GroupEmployeeByDepartment
    {
        public Department Department { get; set; }
        public List<Employee> Employees { get; set; }
    }
}

Next, modify the Main method of the Program class as follows. Here, you can see, we are projecting the result to the above-created GroupEmployeeByDepartment type.

using System.Linq;
using System;
namespace LINQGroupJoin
{
    class Program
    {
        static void Main(string[] args)
        {
            //Group Employees by Department using Method Syntax
            var GroupJoinMS = Department.GetAllDepartments(). //Outer Data Source i.e. Departments
                GroupJoin( //Performing Group Join with Inner Data Source
                    Employee.GetAllEmployees(), //Inner Data Source
                    dept => dept.ID, //Outer Key Selector  i.e. the Common Property
                    emp => emp.DepartmentId, //Inner Key Selector  i.e. the Common Property

                    //Projecting the Result to a Named Type
                    (dept, emp) => new GroupEmployeeByDepartment
                    {
                        Department = dept,
                        Employees = emp.ToList()
                    }
                );

            //Group Employees by Department using Query Syntax
            var GroupJoinQS = from dept in Department.GetAllDepartments() //Outer Data Source i.e. Departments
                              join emp in Employee.GetAllEmployees() //Joining with Inner Data Source i.e. Employees
                              on dept.ID equals emp.DepartmentId //Joining Condition
                              into EmployeeGroups //Projecting the Joining Result into EmployeeGroups

                              //Projecting the Result to a Named Type
                              select new GroupEmployeeByDepartment
                              {
                                  Department = dept,
                                  Employees = EmployeeGroups.ToList()
                              };

            foreach (var item in GroupJoinQS)
            {
                Console.WriteLine("Department :" + item.Department.Name);
                foreach (var employee in item.Employees)
                {
                    Console.WriteLine("  EmployeeID : " + employee.ID + " , Name : " + employee.Name);
                }
            }

            Console.ReadLine();
        }
    }
}

With the above changes in place, run the application code and it will give you the following output.

Example to Understand LINQ GroupJoin Using Query Syntax in C#

Projecting to Anonymous Type with User-Defined Property Names in ResultSet:

It is also possible to specify user-defined names in the result set. For a better understanding, please have a look at the following example. In the below example, we are projecting the result to an anonymous type with user-defined property names. The following example is the same as the previous example except we are projecting to an anonymous type.

using System.Linq;
using System;
namespace LINQGroupJoin
{
    class Program
    {
        static void Main(string[] args)
        {
            //Group Employees by Department using Method Syntax
            var GroupJoinMS = Department.GetAllDepartments(). //Outer Data Source i.e. Departments
                GroupJoin( //Performing Group Join with Inner Data Source
                    Employee.GetAllEmployees(), //Inner Data Source
                    dept => dept.ID, //Outer Key Selector  i.e. the Common Property
                    emp => emp.DepartmentId, //Inner Key Selector  i.e. the Common Property

                    //Projecting the Result with User Defined Names
                    (dept, emp) => new
                    {
                        Department = dept,
                        Employees = emp.ToList()
                    }
                );

            //Group Employees by Department using Query Syntax
            var GroupJoinQS = from dept in Department.GetAllDepartments() //Outer Data Source i.e. Departments
                              join emp in Employee.GetAllEmployees() //Joining with Inner Data Source i.e. Employees
                              on dept.ID equals emp.DepartmentId //Joining Condition
                              into EmployeeGroups //Projecting the Joining Result into EmployeeGroups

                              //Projecting the Result with User Defined Names
                              select new 
                              {
                                  Department = dept,
                                  Employees = EmployeeGroups.ToList()
                              };

            foreach (var item in GroupJoinQS)
            {
                Console.WriteLine("Department :" + item.Department.Name);
                foreach (var employee in item.Employees)
                {
                    Console.WriteLine("  EmployeeID : " + employee.ID + " , Name : " + employee.Name);
                }
            }

            Console.ReadLine();
        }
    }
}
Output:

Projecting to Anonymous Type with User-Defined Property Names in ResultSet

In the next article, I am going to discuss the LINQ Left Outer Join in C# with Examples. In this article, I try to explain the LINQ GroupJoin using both Method and Query Syntax Examples in C#. I hope you enjoy this LINQ GroupJoin Method in C# with Examples article.

Leave a Reply

Your email address will not be published. Required fields are marked *