使用 LINQ 左连接

发布于 2024-07-19 17:45:48 字数 46 浏览 7 评论 0原文

有人能给我一个如何使用 LINQ/lambda 表达式执行左连接操作的示例吗?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

浅语花开 2024-07-26 17:45:48

MSDN 上的 LINQ to SQL 示例页面 给出了以下示例如何实现这一点。 LINQ to Objects 的代码应该几乎相同。

这里的关键是对 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}

如果您需要帮助将其转换为 C#,请询问。

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.

白色秋天 2024-07-26 17:45:48

例如:

IQueryable<aspnet_UsersInRole> q = db.aspnet_Roles
                    .Select(p => p.aspnet_UsersInRoles
                        .SingleOrDefault(x => x.UserId == iduser));

将为您提供 ASP.NET 成员资格中的角色列表,其中与指定用户(iduser 键)不匹配的位置为空

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)

吾性傲以野 2024-07-26 17:45:48

我发现我喜欢的方式是将 OuterCollection.SelectMany() 与 InnerCollection.DefaultIfEmpty() 结合起来。 您可以使用“C# 语句”模式在 LINQPad 中运行以下命令。

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

在对此进行试验时,我发现有时您可以在匿名类型的实例化中省略 player 的空检查。 我认为在数据库上使用 LINQ-to-SQL 时就是这种情况(而不是这里的这些数组,我认为这使其成为 LINQ 到对象或其他东西。)我认为省略 null 检查在 LINQ 中有效-to-SQL,因为查询被转换为 SQL LEFT OUTER JOIN,它直接跳到将 null 与外部项连接起来。 (请注意,匿名对象的属性值必须可为空;因此,如果您想安全地包含 int,比如说,您需要类似以下内容的内容:new { TeamId = (int?)玩家.TeamId }

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

兮颜 2024-07-26 17:45:48

好吧,我尝试重现著名的左连接,其中 b 键为空,我得到的结果是这个扩展方法(只要发挥一点想象力,您可以修改它以仅进行左连接):

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

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;
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文