如何在 LINQ to SQL 中编写右侧为空的 LEFT OUTER JOIN?

Posted

技术标签:

【中文标题】如何在 LINQ to SQL 中编写右侧为空的 LEFT OUTER JOIN?【英文标题】:How to write a LEFT OUTER JOIN where the right side is null in LINQ to SQL? 【发布时间】:2021-03-01 16:15:19 【问题描述】:

如何在 LINQ to SQL 中编写 LEFT OUTER JOIN,其中右侧为空?

我想要的结果的图形表示是这样的:

图片来源Jeff Atwood。

以这条 SQL 为例:

select Document.*
from Document left outer join Invoice
     on Document.DocumentId = Invoice.DocumentId
where Invoice.DocumentId is null

基本上我想要所有不是发票而是其他类型的文件的文件,没关系。

我将非常感谢 LINQ 查询语法和 LINQ 方法(流利)语法中的示例。

谢谢!

【问题讨论】:

也许这会有所帮助:linq-to-sql-left-outer-join @RyanWilson 不过,这并不是真正的左连接 【参考方案1】:

首先,即使在 SQL 中,查询确实应该是 not exists,但通常是 more efficient than the left join / is null construct。

编译器也更好地理解exists,因为它理解not exists 不能向结果集中添加更多行,因此它可以保留任何可能存在的唯一性保证。编译器没有看到带有is null 检查的left join 不能添加行(也许应该,但目前没有内置的逻辑可以这样做)。

select Document.*
from Document
where not exists (select 1
    from Invoice
    where Document.DocumentId = Invoice.DocumentId);

现在很明显如何在 Linq 中做到这一点:

var docs =
    from doc in Documents
    where !Invoices.Any(inv => doc.DocumentId == inv.DocumentId);

var docs =
    Documents
    .Where(doc => !Invoices.Any(inv => doc.DocumentId == inv.DocumentId));

【讨论】:

伟大的查理!谢谢。 @charlieface 我建议阅读更多关于 TSQL 中的 LEFT OUTER JOIN 的信息 - subquery-or-leftouter-join-performance-wise。虽然您的回答有效,但我不相信您关于 LEFT JOIN 效率较低的说法是正确的。 @RyanWilson 您可以从阅读 this article by Aaron Bertrand 开始。我还将告诉您,当编译器可以保证特定连接不会向先前的结果添加更多行时,它通常会获得优势。它只能对半连接或反连接执行此操作,而不是左连接/为空构造。我同意你的观点,编译器应该有这样的逻辑,但今天它不存在。我把那个帖子读到了最后,但看不到任何内容可以改变我的想法。 @RyanWilson 已经进一步澄清了 确实,这是常规左连接的方法,Stack Overflow 上已经有一百个这样的帖子。但是您的问题并没有这么说,您的问题是“如何在 LINQ to SQL 中编写 LEFT OUTER JOIN,其中右侧为空?”答案是将其重写为not exists

以上是关于如何在 LINQ to SQL 中编写右侧为空的 LEFT OUTER JOIN?的主要内容,如果未能解决你的问题,请参考以下文章

Linq-to-SQL 数据库文件为空

LINQ To Objects - 加入空列表

如何在 Linq 的 where 条件下从可为空的日期时间中删除时间部分

如何编写这个 Linq-to-SQL 选择查询

当我不想要的时候,Linq to SQL Join 允许 Nulls

如何在 Web 服务 asp.net 中返回 linq to sql 查询结果?