Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
How to perform a left outer join using linq extension methods in C#?
In LINQ, a Left Outer Join includes all elements from the left collection and matching elements from the right collection. When there's no match in the right collection, the result still includes the left element with null values for the right side.
This is different from an Inner Join, which only includes matching elements from both collections. Left Outer Join ensures that no records from the left collection are lost, even when they don't have corresponding matches in the right collection.
Syntax
The Left Outer Join pattern using LINQ extension methods follows this structure −
leftCollection
.GroupJoin(rightCollection,
leftKey => leftKey.Property,
rightKey => rightKey.Property,
(left, rightGroup) => new { left, rightGroup })
.SelectMany(x => x.rightGroup.DefaultIfEmpty(),
(combined, right) => new {
LeftProperty = combined.left.Property,
RightProperty = right?.Property ?? "Default Value"
})
Example
Consider the following Employee and Department classes. Notice that Employee Mary does not have a department assigned (DepartmentID is 0). A Left Outer Join will include her record with "No Department", while an Inner Join would exclude her −
using System;
using System.Collections.Generic;
using System.Linq;
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 = "Mark", DepartmentID = 1 },
new Employee { ID = 2, Name = "Steve", DepartmentID = 2 },
new Employee { ID = 3, Name = "Ben", DepartmentID = 1 },
new Employee { ID = 4, Name = "Philip", DepartmentID = 1 },
new Employee { ID = 5, Name = "Mary", DepartmentID = 0 }
};
}
}
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 = 1, Name = "IT" },
new Department { ID = 2, Name = "HR" }
};
}
}
static class Program {
static void Main(string[] args) {
var result = Employee.GetAllEmployees()
.GroupJoin(Department.GetAllDepartments(),
e => e.DepartmentID,
d => d.ID,
(emp, depts) => new { emp, depts })
.SelectMany(z => z.depts.DefaultIfEmpty(),
(a, b) => new {
EmployeeName = a.emp.Name,
DepartmentName = b == null ? "No Department" : b.Name
});
Console.WriteLine("Employee Name\tDepartment Name");
Console.WriteLine("=================================");
foreach (var v in result) {
Console.WriteLine(v.EmployeeName + "\t\t" + v.DepartmentName);
}
}
}
The output of the above code is −
Employee Name Department Name ================================= Mark IT Steve HR Ben IT Philip IT Mary No Department
How It Works
The Left Outer Join works in two steps −
-
GroupJoin − Groups matching departments for each employee. If no department matches, an empty group is created.
-
SelectMany with DefaultIfEmpty − Flattens the grouped results.
DefaultIfEmpty()ensures that employees with no matching departments still appear in the result with a null department.
Using Method Syntax vs Query Syntax
The same Left Outer Join can be expressed using query syntax −
using System;
using System.Collections.Generic;
using System.Linq;
static class Program {
static void Main(string[] args) {
var employees = Employee.GetAllEmployees();
var departments = Department.GetAllDepartments();
var queryResult = from emp in employees
join dept in departments on emp.DepartmentID equals dept.ID into deptGroup
from d in deptGroup.DefaultIfEmpty()
select new {
EmployeeName = emp.Name,
DepartmentName = d?.Name ?? "No Department"
};
Console.WriteLine("Using Query Syntax:");
foreach (var item in queryResult) {
Console.WriteLine(item.EmployeeName + " - " + item.DepartmentName);
}
}
}
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 = "Mark", DepartmentID = 1 },
new Employee { ID = 2, Name = "Steve", DepartmentID = 2 },
new Employee { ID = 3, Name = "Ben", DepartmentID = 1 },
new Employee { ID = 4, Name = "Mary", DepartmentID = 0 }
};
}
}
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 = 1, Name = "IT" },
new Department { ID = 2, Name = "HR" }
};
}
}
The output of the above code is −
Using Query Syntax: Mark - IT Steve - HR Ben - IT Mary - No Department
Conclusion
Left Outer Join in C# LINQ combines GroupJoin with SelectMany and DefaultIfEmpty() to include all records from the left collection, even when there are no matches in the right collection. This ensures no data is lost from the primary collection during the join operation.
