左外连接

此查询是否等效于 LEFT OUTER联接?

//assuming that I have a parameter named 'invoiceId' of type int
from c in SupportCases
let invoice = c.Invoices.FirstOrDefault(i=> i.Id == invoiceId)
where (invoiceId == 0 || invoice != null)
select new
{
Id = c.Id
, InvoiceId = invoice == null ? 0 : invoice.Id
}
163762 次浏览

不完全是-因为 left-out-join 中的每个“ left”行将匹配0-n 个“ right”行(在第二个表中) ,而-as 只匹配0-1。要做一个左外部连接,你需要 SelectManyDefaultIfEmpty,例如:

var query = from c in db.Customers
join o in db.Orders
on c.CustomerID equals o.CustomerID into sr
from x in sr.DefaultIfEmpty()
select new {
CustomerID = c.CustomerID, ContactName = c.ContactName,
OrderID = x == null ? -1 : x.OrderID };

(或通过扩展方法)

Public Sub LinqToSqlJoin07()
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}


ObjectDumper.Write(q) End Sub

检查 http://msdn.microsoft.com/en-us/vbasic/bb737929.aspx

我找到了一个解决方案。如果想把这种 SQL (左连接)转换成 Linq 实体..。

SQL:

SELECT * FROM [JOBBOOKING] AS [t0]
LEFT OUTER JOIN [REFTABLE] AS [t1] ON ([t0].[trxtype] = [t1].[code])
AND ([t1]. [reftype] = "TRX")

林克:

from job in JOBBOOKINGs
join r in (from r1 in REFTABLEs where r1.Reftype=="TRX" select r1)
on job.Trxtype equals r.Code into join1
from j in join1.DefaultIfEmpty()
select new
{
//cols...
}

你不需要 into 的陈述:

var query =
from customer in dc.Customers
from order in dc.Orders
.Where(o => customer.CustomerId == o.CustomerId)
.DefaultIfEmpty()
select new { Customer = customer, Order = order }
//Order will be null if the left join is null

是的,上面的查询确实创建了 LEFT OUTER 连接。

链接到处理多个左连接的类似问题: Linq 到 Sql: 多个左外部连接

我还想补充一点。在 LINQtoSQL 中,如果数据库构建正确,并且表通过外键约束相关,那么根本不需要进行连接。

使用 LINQPad 我创建了以下 LINQ 查询:

//Querying from both the CustomerInfo table and OrderInfo table
from cust in CustomerInfo
where cust.CustomerID == 123456
select new {cust, cust.OrderInfo}

该查询被转换为下面的(略微截断的)查询

 -- Region Parameters
DECLARE @p0 Int = 123456
-- EndRegion
SELECT [t0].[CustomerID], [t0].[AlternateCustomerID],  [t1].[OrderID], [t1].[OnlineOrderID], (
SELECT COUNT(*)
FROM [OrderInfo] AS [t2]
WHERE [t2].[CustomerID] = [t0].[CustomerID]
) AS [value]
FROM [CustomerInfo] AS [t0]
LEFT OUTER JOIN [OrderInfo] AS [t1] ON [t1].[CustomerID] = [t0].[CustomerID]
WHERE [t0].[CustomerID] = @p0
ORDER BY [t0].[CustomerID], [t1].[OrderID]

注意上面的 LEFT OUTER JOIN

注意表现:

我体验到,至少在 EF Core中,这里给出的不同答案可能会导致不同的表现。我知道 OP 询问了 Linq to SQL,但在我看来,同样的问题也出现在 EF Core 上。

在我必须处理的一个特定案例中,Marc Gravell 提出的(语法上更好)建议导致在交叉应用程序中出现左连接——与 Mike U 描述的类似—— 其结果是,与没有交叉连接的查询相比,此特定查询的估计成本高出两倍。服务器执行次数乘以 相差三倍。[1]

Marc Gravell 的解决方案导致了一个没有交叉连接的查询。

上下文: 我实际上需要在两个表上执行两个左联接,每个表又需要一个到另一个表的联接。此外,我还必须在需要应用左连接的表上指定其他 where 条件。 此外,我在主表上有两个内部连接。

估计运营成本:

  • 交叉申请: 0.2534
  • 无交叉申请: 0.0991。

以 ms 为单位的服务器执行时间(查询执行10次; 使用 SET STATISTICS TIME ON 测量) :

  • 交叉申请: 5,6,6,6,6,6,6,6,6,6,6,6,6
  • 无交叉适用: 2,2,2,2,2,2,2,2,2,2

(对于这两个查询,第一次运行的速度都比较慢; 似乎缓存了一些内容。)

餐桌大小:

  • 主表: 87行,
  • 左连接的第一个表: 179行;
  • 第二个左连接表: 7行。

EF Core 版本: 2.2.1。

SQLServer 版本: MSSQLServer2017-14... (在 Windows10上)。

所有相关表只有主键上的索引。

我的结论是: 总是建议查看生成的 SQL,因为它们可能真的有所不同。


[1]有趣的是,当在 MS SQL Server Management Studio 中设置“客户端统计信息”时,我可以看到一个相反的趋势; 即上一次没有交叉应用的解决方案运行花费了超过1s。我想这里出了点问题——也许是我的设置出了问题。