単純なLEFT OUTER結合のためにEFCoreが多すぎる列を返す

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各列には大きな問題があります。

[OrderSummary]、[Order]、[Order]、[Order]、[Order]、[Order]、[ParentFSPId]、[注文] [ParentOrderId]、[注文]。[PayPalECToken]、[注文]。[PaymentFailureTypeId] ....

[OrderItem]。[OrderItem]。[orderItem]。[OrderItem]。[orderItem]。[Qty]、[orderItem]。[SKU] FROM [Order] AS [order] LEFT JOIN [OrderItem] AS [orderItem] ] [注文] [注文ID] = [注文アイテム]。[注文ID] ORDER BY [注文]。[注文ID]

(ここにはさらに多くの列が表示されていません。)

一方、 - それをINNER JOINにすると、select節のカラムだけでSQLが期待どおりになります。

[注文] IN [注文品] AS [注文品] ON [注文品] = [注文品]から[注文] [orderItem]。[OrderId]

私はEFCore 1.01に復帰しようとしましたが、恐ろしいナゲットパッケージのエラーがあり、それをあきらめました。

これが実際の回帰問題であるか、EFCoreでの不完全な機能であるかは不明です。しかし、これに関する他の情報は見つけられませんでした。


編集:EFCore 2.1は、グループ化に関する多くの問題に対処しました。また、N + 1タイプの問題では、すべての子エンティティに対して個別のクエリが行われます。実際にはパフォーマンスに非常に感銘を受けました。

3/14/18 - 2.1 EFCoreのプレビュー1は推奨されていません。なぜなら、OrderBy()を使用するとGROUP BY SQLにいくつかの問題がありますが、夜間ビルドとプレビュー2では修正されているからです。

受け入れられた回答

以下はEF Core 1.1.0(リリース)に適用されます。

このようなことはしないでください(手動結合の代わりにナビゲーションプロパティを使用し、匿名型の射影を含むサブクエリを結合する、 let / intermediate Selectを使う、 Concat / Unionを使って左結合をエミュレートする、代替左結合構文など) )結果は、投稿と同じか、複数のクエリを実行するか、無効なSQLクエリ、および/またはIndexOutOfRangeInvalidArgumentなどの異常な実行時例外です。

私がテストに基づいて言うことができるのは、 GroupJoin翻訳でバグ(回帰、不完全な実装 - 本当に重要です)に関連する可能性が最も高いということです。たとえば、 #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]

ご覧のとおり、投影はOKですが、 LEFT JOIN代わりに、 CROSS APPLYという奇妙なものが使用され、別のパフォーマンス上の問題が発生する可能性があります。

また、上記のように右側の結合テーブルにアクセスするときは、値型にはキャストを使用し、文字列にはキャストを使用しないでください。元のクエリのようにnullチェックを使用すると、実行時にArgumentNullExceptionします(さらに別のバグ)。



Related

ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ
ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ