EFCore為簡單的LEFT OUTER連接返回了太多列

entity-framework entity-framework-core

我目前正在使用SQL Server的EFCore 1.1(預覽版)。

我正在做我認為OrderOrderItem表之間的簡單OUTER JOIN。

      var orders = from order in ctx.Order
                   join orderItem in ctx.OrderItem

                   on order.OrderId equals orderItem.OrderId into tmp

                   from oi in tmp.DefaultIfEmpty()

                   select new
                   {
                       order.OrderDt,
                       Sku = (oi == null) ? null : oi.Sku,
                       Qty = (oi == null) ? (int?) null : oi.Qty
                   };

返回的實際數據是正確的(我知道早期版本的OUTER JOINS根本沒有工作的問題)。然而,SQL很糟糕,包括OrderOrderItem每一列,這是有問題的,因為其中一個是一個大的XML Blob。

SELECT [order]。[OrderId],[order]。[OrderStatusTypeId],[order]。[OrderSummary],[order]。[OrderTotal],[order]。[OrderTypeId],[order]。[ParentFSPId],[訂單]。[ParentOrderId],[order]。[PayPalECToken],[order]。[PaymentFailureTypeId] ....

... [orderItem]。[OrderId],[orderItem]。[OrderItemType],[orderItem]。[Qty],[orderItem]。[SKU] FROM [Order] AS [order] LEFT JOIN [OrderItem] AS [orderItem ] ON [order]。[OrderId] = [orderItem]。[OrderId] ORDER BY [order]。[OrderId]

(此處未顯示更多列。)

另一方面 - 如果我使它成為INNER JOIN,那麼SQL就像預期的那樣只有我的select子句中的列:

SELECT [order]。[OrderDt],[orderItem]。[SKU],[orderItem]。[Qty] FROM [Order] AS [order] INNER JOIN [OrderItem] AS [orderItem] ON [order]。[OrderId] = [OrderItem的]。[單編號]

我嘗試恢復到EFCore 1.01,但得到了一些可怕的nuget包錯誤並放棄了。

不清楚這是EFCore中的實際回歸問題還是不完整的功能。但在其他地方找不到任何關於此的進一步信息。


編輯:EFCore 2.1解決了很多分組問題以及N + 1類型問題,其中為每個子實體進行單獨查詢。實際上對性能印象非常深刻。

3/14/18 - 2.1不建議使用EFCore預覽1,因為GROUP BY SQL在使用OrderBy()時有一些問題,但它在夜間構建和預覽2中已得到修復。

一般承認的答案

以下內容適用於EF Core 1.1.0(發行版)。

雖然不應該這樣做,但嘗試了幾種替代語法查詢(使用導航屬性而不是手動連接,加入包含匿名類型投影的子查詢,使用let / intermediate Select ,使用Concat / Union模擬左連接,替代左連接語法等) 。)結果 - 與post中相同,和/或執行多個查詢,和/或無效的SQL查詢,和/或奇怪的運行時異常,如IndexOutOfRangeInvalidArgument等。

基於測試我可以說的是,很可能這個問題與GroupJoin翻譯中的bug(回歸,不完整的實現 - 確實很重要)有關。例如, #7003:在最終投影中不存在的子查詢上使用組連接進行查詢時生成錯誤的SQL#6647 - 左連接(GroupJoin)始終實現導致不必要數據拉取的元素等。

直到它被修復(何時?),作為一個(遠非完美的)解決方法,我可以建議使用替代的左外連接語法( from a in A from b in B.Where(b = b.Key == a.Key).DefaultIfEmpty() ):

var orders = from o in ctx.Order
             from oi in ctx.OrderItem.Where(oi => oi.OrderId == o.OrderId).DefaultIfEmpty()
             select new
             {
                 OrderDt = o.OrderDt,
                 Sku = oi.Sku,
                 Qty = (int?)oi.Qty
             };

它產生以下SQL:

SELECT [o].[OrderDt], [t1].[Sku], [t1].[Qty]
FROM [Order] AS [o]
CROSS APPLY (
    SELECT [t0].*
    FROM (
        SELECT NULL AS [empty]
    ) AS [empty0]
    LEFT JOIN (
        SELECT [oi0].*
        FROM [OrderItem] AS [oi0]
        WHERE [oi0].[OrderId] = [o].[OrderId]
    ) AS [t0] ON 1 = 1
) AS [t1]

正如您所看到的,投影是正常的,但它不使用LEFT JOIN而是使用奇怪的CROSS APPLY ,這可能會引入另一個性能問題。

另請注意,在訪問右連接表時,必須使用強制類型轉換為字符串,而不是字符串,如上所示。如果在原始查詢中使用null檢查,則會在運行時獲得ArgumentNullException (還有另一個錯誤)。



Related

許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因
許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因