C#实体框架核心,左联接中的内部选择

时间:2020-10-12 12:12:13

标签: c# sql-server entity-framework entity-framework-core

我想使用实体框架使以下SQL Server等效。原始SQL如下:

SELECT 
C.CustomerID, 
P.Title,
P.FirstName, 
P.LastName,
SOH.SalesOrderNumber,
SOH.SubTotal, 
SOH.TotalDue, 
SOH.OrderDate, 
SOH.ShipDate,
SOD.UnitPrice, 
SOD.LineTotal
FROM Sales.Customer AS C
INNER JOIN Person.Person AS P ON P.BusinessEntityID = C.PersonID
LEFT JOIN Sales.SalesOrderHeader AS SOH ON SOH.CustomerID = C.CustomerID
LEFT JOIN Sales.SalesOrderDetail AS SOD ON SOD.SalesOrderID = SOH.SalesOrderID
WHERE P.FirstName = 'Aaron'

这个C#似乎很接近,但是它并没有进行很好的联接,而是进行了内部选择

using (var db = new AdventureWorks2014Context())
{
    var queryable = db.Customer
        .Include(c => c.Person)
        .Include(c => c.SalesOrderHeader)
        .ThenInclude(soh => soh.SalesOrderDetail)
        .Where(x => x.Person.FirstName == name)
        .Select(c => new CustomerOrderDetails
        {
            CustomerId = c.CustomerId, 
            Title = c.Person.Title,
            FirstName = c.Person.FirstName, 
            LastName = c.Person.LastName, 
            SalesOrderHeaderLine = c.SalesOrderHeader.Select(soh => new CustomerSalesOrderHeaderLine
            {
                SubTotal = soh.SubTotal, 
                TotalDue = soh.TotalDue,
                OrderDate = soh.OrderDate,
                ShipDate = soh.ShipDate, 
                SalesOrderLine = soh.SalesOrderDetail.Select(so => new CustomerSalesOrderLine
                {
                    LineTotal = so.LineTotal, 
                    UnitPrice = so.UnitPrice
                })
            })
        });

    return queryable.ToList();
}

这是上面代码生成的SQL

exec sp_executesql N'
SELECT 
[c].[CustomerID], 
[p].[Title], 
[p].[FirstName], 
[p].[LastName], 
[t].[SubTotal], 
[t].[TotalDue], 
[t].[OrderDate], 
[t].[ShipDate], 
[t].[SalesOrderID], 
[t].[LineTotal], 
[t].[UnitPrice], 
[t].[SalesOrderID0], 
[t].[SalesOrderDetailID]
FROM [Sales].[Customer] AS [c]
LEFT JOIN [Person].[Person] AS [p] ON [c].[PersonID] = [p].[BusinessEntityID]
LEFT JOIN (
    SELECT [s].[SubTotal], [s].[TotalDue], [s].[OrderDate], [s].[ShipDate], [s].[SalesOrderID], [s0].[LineTotal], [s0].[UnitPrice], [s0].[SalesOrderID] AS [SalesOrderID0], [s0].[SalesOrderDetailID], [s].[CustomerID]
    FROM [Sales].[SalesOrderHeader] AS [s]
    LEFT JOIN [Sales].[SalesOrderDetail] AS [s0] ON [s].[SalesOrderID] = [s0].[SalesOrderID]
) AS [t] ON [c].[CustomerID] = [t].[CustomerID]
WHERE [p].[FirstName] = @__name_0
ORDER BY [c].[CustomerID], [t].[SalesOrderID], [t].[SalesOrderID0], [t].[SalesOrderDetailID]',N'@__name_0 nvarchar(50)',@__name_0=N'Aaron'

是否可以编写C#,使其仅使用左连接,与我的原始查询(在顶部)相同?因为我不希望内部选择。这表现不佳。我不希望在销售订单抬头和详细信息上进行内部选择。我想要它,因为我写了原始照片(在顶部)。纯SQL的页面读取更少的页面,扫描更少。

请注意,我正在尝试将其编写为与纯SQL查询一样好(由于布伦特·奥扎尔(brent ozar)的知识,我已经学到了很多东西)。我知道它将为我提供所需的信息,但是我希望能够编写与我希望SQL编写的方式非常接近的EF,因为当您的产品具有数百万行并且速度很慢时(因为EF已经生成),这样做就不好了SQL的脏转储。对于这种情况,“客户”扫描计数已从1增加到56,并且逻辑读取次数增加了一倍,效果不佳。

1 个答案:

答案 0 :(得分:0)

因此,在Svyatosalav Danyliv回答后,似乎这是EF Core的局限性。

这是GitHub上的已知问题。

无论我尝试采用EF多少,它都没有自己编写SQL一样好。