「トップ」オブジェクトが 0 ~ N 個の「サブ」オブジェクトを持つデータ モデルがあります。SQL では、これは外部キーで実現されますdbo.Sub.TopId
。
var query = context.Top
//.Include(t => t.Sub) Doesn't seem to do anything
.Select(t => new {
prop1 = t.C1,
prop2 = t.Sub.Select(s => new {
prop21 = s.C3 //C3 is a column in the table 'Sub'
})
//.ToArray() results in N + 1 queries
});
var res = query.ToArray();
Entity Framework 6 (遅延読み込みオフ) では、この Linq クエリは単一のSQL クエリに変換されます。結果は完全にロードされるため、res[0].prop2
すでにIEnumerable<SomeAnonymousType>
満たされた になります。
ただし、EntityFrameworkCore (NuGet v1.1.0) を使用する場合、サブコレクションはまだ読み込まれておらず、次のタイプです。
System.Linq.Enumerable.WhereSelectEnumerableIterator<Microsoft.EntityFrameworkCore.Storage.ValueBuffer, <>f__AnonymousType1<string>>.
データを反復処理するまでデータはロードされないため、N + 1 クエリが発生します。.ToArray()
(コメントに示されているように) クエリに追加すると、データは に完全にロードされますがvar res
、SQL プロファイラーを使用すると、これが 1 つの SQL クエリでは達成されないことがわかります。「トップ」オブジェクトごとに、「サブ」テーブルに対するクエリが実行されます。
最初に指定.Include(t => t.Sub)
しても何も変わらないようです。匿名型の使用も問題ではないようです。new { ... }
ブロックを置き換えてnew MyPocoClass { ... }
も何も変わりません。
私の質問は次のとおりです。すべてのデータがすぐに読み込まれる EF6 と同様の動作を取得する方法はありますか?
注:この例では、次のようにクエリを実行した後、メモリ内に匿名オブジェクトを作成することで問題を解決できることを認識しています。
var query2 = context.Top
.Include(t => t.Sub)
.ToArray()
.Select(t => new //... select what is needed, fill anonymous types
ただし、これは単なる例です。実際には、オブジェクトの作成を Linq クエリの一部にする必要があります。これは、AutoMapper がこれを使用してプロジェクトの DTO を埋めるためです。
更新:新しい EF Core 2.0 でテストしましたが、問題はまだ存在しています。(2017 年 8 月 21 日)
aspnet/EntityFrameworkCore
問題はGitHub リポジトリで追跡されています:問題 4007
更新: 1 年後、この問題はバージョン で修正されました2.1.0-preview1-final
。(2018-03-01)
更新: EF バージョン 2.1 がリリースされました。これには修正が含まれています。以下の私の答えを見てください。(2018-05-31)