Summary: in this tutorial, you’ll learn how to use the LINQ Join()
method to perform an inner join of two sequences based on one or more keys.
Introduction to the LINQ Inner Join
To join two sequences based on one or more keys, you use the LINQ Join()
extension method. Here’s the syntax of the Join()
method:
public static IEnumerable<TResult> Join<TOuter,TInner,TKey,TResult> (
this IEnumerable<TOuter> outer,
IEnumerable<TInner> inner,
Func<TOuter,TKey> outerKeySelector,
Func<TInner,TKey> innerKeySelector,
Func<TOuter,TInner,TResult> resultSelector
);
Code language: C# (cs)
In this syntax:
outer
is the first sequence to join.inner
is the sequence that joins to the first sequence.outerKeySelector
is a function that extracts the join key from each element of the first sequence.innerKeySelector
is a function that extracts the join key from each element of the second sequence.resultSelector
is a function that creates the result element from two matching elements.
The Join()
method returns an IEnumerable<TResult>
that has elements as the result of an inner join on the two sequences.
LINQ Inner Join examples
Let’s take some examples of using the LINQ Join()
method to perform an inner join.
1) Using LINQ Join() method to perform an inner join based on a single key
The following program demonstrates how to use the Join()
method to join the products list to the item list based on the product id:
class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Cost { get; set; }
public Product(int id, string name, decimal cost)
{
Id = id;
Name = name;
Cost = cost;
}
}
class Item
{
public int ProductId { get; set; }
public int Qty { get; set; }
public decimal Price { get; set; }
public Item(int productId, int qty, decimal price)
{
ProductId = productId;
Qty = qty;
Price = price;
}
}
class Program
{
public static void Main(string[] args)
{
var products = new List<Product>()
{
new (id: 1, name: "A", cost: 10),
new (id: 2, name: "B", cost: 20),
new (id: 3, name: "C", cost: 30)
};
var items = new List<Item>()
{
new (productId:1, qty: 2, price: 12),
new (productId:2, qty: 2, price: 25),
new (productId:3, qty: 4, price: 35)
};
var results = items.Join(
products,
item => item.ProductId,
product => product.Id,
(item, product) => new
{
product.Name,
product.Cost,
item.Price,
item.Qty,
Margin = (item.Price - product.Cost) * item.Qty
}
);
foreach (var result in results)
{
Console.WriteLine(result);
}
}
}
Code language: C# (cs)
How it works.
First, define a Product
class that has three properties Id
, Name
, and Cost
.
class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Cost { get; set; }
public Product(int id, string name, decimal cost)
{
Id = id;
Name = name;
Cost = cost;
}
}
Code language: C# (cs)
Second, define the Item
class that has three properties ProductId
, Qty
, and Price
:
class Item
{
public int ProductId { get; set; }
public int Qty { get; set; }
public decimal Price { get; set; }
public Item(int productId, int qty, decimal price)
{
ProductId = productId;
Qty = qty;
Price = price;
}
}
Code language: C# (cs)
The ProductId
of the Item
class matches the Id
of the Product
class.
Third, create a list of three Product
objects in the Main()
method of the Program
class:
var products = new List<Product>()
{
new (id: 1, name: "A", cost: 10),
new (id: 2, name: "B", cost: 20),
new (id: 3, name: "C", cost: 30)
};
Code language: C# (cs)
Fourth, create a list of three Items:
var items = new List<Item>()
{
new (productId:1, qty: 2, price: 12),
new (productId:2, qty: 2, price: 25),
new (productId:3, qty: 4, price: 35)
};
Code language: C# (cs)
Fifth, join the product list with the items list based on the product id:
var results = items.Join(
products,
item => item.ProductId,
product => product.Id,
(item, product) => new
{
product.Name,
product.Cost,
item.Price,
item.Qty,
Margin = (item.Price - product.Cost) * item.Qty
}
);
Code language: C# (cs)
The Join()
method joins the products and items list based on the common property:
ProductId
inItem
in theitems
list.Id
ofProduct
in theproducts
list.
The result of the inner join is a new sequence of anonymous objects. Each object contains the data from matching Item
and Product
objects in both sequences.
The Join()
method takes four arguments:
- The first argument is the products list which is the sequence to join with.
- The second argument is a lambda expression that defines the matching property in the items list –
item=> item.ProductId
. - The third argument is a lambda expression that defines the matching property in the products list –
product => product.Id
. - The fourth argument is a lambda expression that defines the shape of the result objects. Each anonymous object has four properties:
Name
,Cost
,Price
,Qty
, andMargin
. TheMargin
property represents the profit margin of each item based on the cost of the product and the price of the item.
Finally, display the result of the join to the console using a foreach
loop and WriteLine()
method.
The following shows the query syntax that is equivalent to the above method syntax:
var results = from product in products
join item in items on product.Id equals item.ProductId
select new
{
product.Name,
product.Cost,
item.Price,
item.Qty,
Margin = (item.Price - product.Cost) * item.Qty
};
Code language: C# (cs)
2) Using LINQ Join() method to perform an inner join based on a composite key
The following program demonstrates how to use the Join()
method to join the candidates
and employees
lists based on first name and last name:
class Candidate
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime InterviewDate { get; set; }
public Candidate(string firstName, string lastName, DateTime interviewDate)
{
FirstName = firstName;
LastName = lastName;
InterviewDate = interviewDate;
}
}
class Employee
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime JoinedDate { get; set; }
public Employee(string firstName, string lastName, DateTime joinedDate)
{
FirstName = firstName;
LastName = lastName;
JoinedDate = joinedDate;
}
}
class Program
{
static void Main(string[] args)
{
// Create a list of candidates
List<Candidate> candidates = new()
{
new ("John", "Doe", new DateTime(2010, 1, 20)),
new ("Jane", "Doe", new DateTime(2010, 1, 28)),
new ("Bob", "Smith",new DateTime(2010, 1, 15))
};
// Create a list of employees
List<Employee> employees = new()
{
new ("John", "Doe", new DateTime(2010, 2, 1)),
new ("Jane", "Doe", new DateTime(2010, 2, 2)),
new ("Alice", "Johnson", new DateTime(2010, 2, 3))
};
var query = candidates.Join(
employees,
candidate => new { candidate.FirstName, candidate.LastName },
employee => new { employee.FirstName, employee.LastName },
(candidate, employee) => new
{
Name = $"{candidate.FirstName} {candidate.LastName}",
candidate.InterviewDate,
employee.JoinedDate
});
foreach (var result in query)
{
Console.WriteLine($"{result.Name} was interviewd on {result.InterviewDate.ToShortDateString()} and joined on {result.JoinedDate.ToShortDateString()}");
}
}
}
Code language: C# (cs)
Output:
John Doe was interviewd on 1/20/2010 and joined on 2/1/2010
Jane Doe was interviewd on 1/28/2010 and joined on 2/2/2010
Code language: C# (cs)
In this example:
First, define two classes: Candidate
and Employee
.
Second, create two lists of candidates and employees that contain the Candidate
and Employee
objects respectively.
Third, join the two lists based on the matching of the FirstName
and LastName
properties. The Join()
method is called on the candidates
list and takes four arguments:
- The
employees
to join with. - A lambda expression that selects the key of the
Candidate
object to join (FirstName
andLastName
) - A lambda expression that selects the key of the
Employee
object to join (FirstName
andLastName
). - A lambda expression that creates a new anonymous object for the result list. The anonymous object contains the
Name
,InterviewDate
, andJoinedDate
properties.
Finally, iterate over the result and write each object to the console.
The following shows the query syntax that is equivalent to the above method syntax:
var query = from candidate in candidates
join employee in employees
on new { candidate.FirstName, candidate.LastName }
equals new { employee.FirstName, employee.LastName }
select new
{
Name = $"{candidate.FirstName} {candidate.LastName}",
candidate.InterviewDate,
employee.JoinedDate
};
Code language: C# (cs)
Summary
- Use LINQ
Join()
method to join two sequences based on one or more keys.