Could someone give me an example of how to perform a left join operation using LINQ/lambda expressions?
For instance:
IQueryable<aspnet_UsersInRole> q = db.aspnet_Roles
.Select(p => p.aspnet_UsersInRoles
.SingleOrDefault(x => x.UserId == iduser));
Will give you a list of roles from the asp.net membership, with nulls where it doesn't match the specified user (iduser key)
Here is an example of a left join in LINQ.
well i tried to reproduce the famous left join where b key is null and the result i got is this extension method (with a little imagination you can modify it to just make a left join):
public static class extends
{
public static IEnumerable<T> LefJoinBNull<T, TKey>(this IEnumerable<T> source, IEnumerable<T> Target, Func<T, TKey> key)
{
if (source == null)
throw new ArgumentException("source is null");
return from s in source
join j in Target on key.Invoke(s) equals key.Invoke(j) into gg
from i in gg.DefaultIfEmpty()
where i == null
select s;
}
}
The way I have found that I like is to combine OuterCollection.SelectMany()
with InnerCollection.DefaultIfEmpty()
. You can run the following in LINQPad using "C# Statements" mode.
var teams = new[]
{
new { Id = 1, Name = "Tigers" },
new { Id = 2, Name = "Sharks" },
new { Id = 3, Name = "Rangers" },
};
var players = new[]
{
new { Name = "Abe", TeamId = 2},
new { Name = "Beth", TeamId = 4},
new { Name = "Chaz", TeamId = 1},
new { Name = "Dee", TeamId = 2},
};
// SelectMany generally aggregates a collection based upon a selector: from the outer item to
// a collection of the inner item. Adding .DefaultIfEmpty ensures that every outer item
// will map to something, even null. This circumstance makes the query a left outer join.
// Here we use a form of SelectMany with a second selector parameter that performs an
// an additional transformation from the (outer,inner) pair to an arbitrary value (an
// an anonymous type in this case.)
var teamAndPlayer = teams.SelectMany(
team =>
players
.Where(player => player.TeamId == team.Id)
.DefaultIfEmpty(),
(team, player) => new
{
Team = team.Name,
Player = player != null ? player.Name : null
});
teamAndPlayer.Dump();
// teamAndPlayer is:
// {
// {"Tigers", "Chaz"},
// {"Sharks", "Abe"},
// {"Sharks", "Dee"},
// {"Rangers", null}
// }
While experimenting with this, I found that sometimes you can omit the null-check of player
in the instantiation of the anonymous type. I think that this is the case when using LINQ-to-SQL on a database (instead of these arrays here, which I think makes it LINQ-to-objects or something.) I think that the omission of the null check works in LINQ-to-SQL because the query is translated into a SQL LEFT OUTER JOIN
, which skips straight to joining null with the outer item. (Note that the value of the anonymous object's property must be nullable; so if you want to safely include an int
, say, you would need something like: new { TeamId = (int?)player.TeamId }
.
The LINQ to SQL samples page on MSDN gives an example of how to accomplish this. The code should be pretty much identical for LINQ to Objects.
The key here is the call to DefaultIfEmpty
.
Dim q = From e In db.Employees _
Group Join o In db.Orders On e Equals o.Employee Into ords = Group _
From o In ords.DefaultIfEmpty _
Select New With {e.FirstName, e.LastName, .Order = o}
If you need help converting that to C#, just ask.