Left join using LINQ

2019-02-16 19:35发布

Could someone give me an example of how to perform a left join operation using LINQ/lambda expressions?

5条回答
放荡不羁爱自由
2楼-- · 2019-02-16 19:46

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.

查看更多
相关推荐>>
3楼-- · 2019-02-16 19:59

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;
    }
}
查看更多
Emotional °昔
4楼-- · 2019-02-16 20:01

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)

查看更多
地球回转人心会变
5楼-- · 2019-02-16 20:02

Here is an example of a left join in LINQ.

查看更多
Bombasti
6楼-- · 2019-02-16 20:07

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

查看更多
登录 后发表回答