使用方法语法实现的 LEFT OUTER JOIN
Posted
技术标签:
【中文标题】使用方法语法实现的 LEFT OUTER JOIN【英文标题】:LEFT OUTER JOIN implemented with method syntax 【发布时间】:2021-12-20 11:50:41 【问题描述】:上下文
Itzik Ben-Gan 的T-SQL Fundamentals Third Edition一书在第 3 章中包含以下查询:
SELECT C.custid, C.companyname, O.orderid
FROM Sales.Customers AS C
LEFT OUTER JOIN Sales.Orders AS O
ON C.custid = O.custid;
我已将其转换为 LINQ,如下所示:
var result =
from customer in db.Customers
join order in db.Orders
on customer.Custid equals order.Custid into Abc
from abc in Abc.DefaultIfEmpty()
select new
customer.Custid,
customer.Companyname,
orderid = abc == null ? -1 : abc.Orderid
;
问题
使用方法语法而不是查询语法来编写上述内容的好方法是什么?
我从这个开始:
var result = db.Customers.Join(
db.Orders,
customer => customer.Custid,
order => order.Custid,
(customer, order) =>
new
customer.Custid,
customer.Companyname,
orderid = order.Orderid
);
但是,这当然会忽略 NULL 值的项目。
我不清楚的部分是如何将into
语法转换为方法语法。
欢迎提出任何建议!
注意事项
如果您真的想自己运行查询,上述查询位于此处提供的项目中:
https://github.com/dharmatech/TSqlEf/blob/master/Chapter3p114/Program.cs
有关如何设置数据库,请参阅项目自述文件:
https://github.com/dharmatech/TSqlEf
【问题讨论】:
@CaiusJard,它不仅缺少DefaultIfEmpty
,而且也没有使用GroupJoin
,这似乎是必需的。
@CaiusJard,感谢您关于发布答案而不是编辑的建议。我已从问题中删除了答案并将其添加为单独的答案。
只有在 Join 丢弃非匹配项(没有任何订单的客户)的意义上它是“必需的”,而 GroupJoin 可以给出“customer_with_list_of_orders_that_may_be_empty”,然后可以用于模拟数据库如何离开联接,因为您拥有这种“列表中具有多个细节的单个主控”结构,可以通过迭代扩展为“N 个主控,具有 N 个细节,每个细节一个重复主控”
【参考方案1】:
对于左连接方法语法,您需要使用 GroupJoin 以及 DefaultIfEmpty 和 SelectMany 方法。尝试使用以下查询,
var result = db.Customers.GroupJoin(
db.Orders,
cust => customer.Custid,
ord => order.Custid,
(cust, ord) => new cust, ord)
.SelectMany(c => c.ord.DefaultIfEmpty(), (customer, order) =>
new
customer.Custid,
customer.Companyname,
orderid = order.Orderid
);
【讨论】:
如果你有比特币地址,请告诉我,我很乐意给你寄东西买午餐。 :-D 你不需要SelectMany. See the
GroupJoin`重载docs.microsoft.com/en-us/dotnet/api/…
(但我也很想知道Aluan是什么意思)
阿銮错了,GroupJoin
不够。它可以只用SelectMany
和相关子查询来完成。然而,所有这些都是通用的 LINQ 方法,而在 EF 中,当使用导航属性而不是手动连接时,事情要简单得多。将所有这些与db.Customers.SelectMany(customer => customer.Orders.DefaultIfEmpty(), (customer, order) => new ... )
进行比较
@IvanStoev,啊...我明白了。这是非常好的。我已经根据您的建议发布了答案。非常感谢!【参考方案2】:
Ivan Stoev 的建议
Ivan 在上面的评论中建议这可以使用导航属性来完成。这是基于他的建议的完整方法:
var result = db.Customers.SelectMany(
customer => customer.Orders.DefaultIfEmpty(),
(customer, order) => new
customer.Custid,
customer.Companyname,
orderid = order == null ? -1 : order.Orderid
);
到目前为止,它似乎是最简单和最直接的。谢谢伊万!
【讨论】:
作为对此的扩展,您甚至可能不需要运行联接。假设你正在准备一份报告,你可以只做foreach(var c in db.Customers.Include(c => c.Orders)) foreach(var o in c.Orders) Console.Writeline$("Customer c.Id has order o.Id");
,也许用if
看看!c.Orders.Any()
是否客户没有订单。本质上,我是说如果你正在生成一些客户一遍又一遍地重复的矩形数据块,纯粹是这样你就可以做foreach(var x in ..someCustomerOrderJoin..)
然后你可能不需要..你可以嵌套循环它
@CaiusJard 啊,好的。我根据您的建议添加了另一个答案。谢谢! ***.com/a/69872705/268581【参考方案3】:
阿布的回答
这是一个基于阿布回答的版本。我必须添加这个条件:
orderid = order == null? -1 : order.Orderid
让它工作。我也改变了一些命名。但是,它似乎确实有效!
var result = db.Customers.GroupJoin(
db.Orders,
customer => customer.Custid,
order => order.Custid,
(customer, orders) => new customer, orders )
.SelectMany(
customer_orders => customer_orders.orders.DefaultIfEmpty(),
(customer_orders, order) => new
customer_orders.customer.Custid,
customer_orders.customer.Companyname,
orderid = order == null? -1 : order.Orderid
);
类似问题
看到这个类似的问题:
LEFT OUTER JOIN in LINQ
它包含一个类似于 Abu 的方法的答案。
【讨论】:
【参考方案4】:Caius Jard 的建议
Caius 提到,出于构建报告的目的,可以采用嵌套的foreach
方法。以下是基于他的建议的一种方法:
foreach (var customer in db.Customers.Include(customer => customer.Orders))
if (customer.Orders.Any())
foreach (var order in customer.Orders)
Console.WriteLine("0 1 2",
customer.Custid,
customer.Companyname,
order.Orderid);
else
Console.WriteLine("0 1 2",
customer.Custid,
customer.Companyname,
-1);
【讨论】:
以上是关于使用方法语法实现的 LEFT OUTER JOIN的主要内容,如果未能解决你的问题,请参考以下文章
SQL的JOIN语法解析(inner join, left join, right join, full outer join的区别)
SQL的JOIN语法解析(inner join, left join, right join, full outer join的区别)
SQL中的left outer join,inner join,right outer join用法详解
SQL的JOIN语法解析(inner join, left join, right join, full outer join的区别)