[更新 - 下部の更新を参照]
私は EF コード ファーストを使用していますが、概ね満足しています。ただし、1 つの単純な (そして一般的な) 操作によって、EF がとてつもなく複雑な SQL を生成し、アプリケーションの速度が低下しています。
(整数) ID のリストを使用して一連のエンティティを取得しているだけですが、多くのサブエンティティの詳細が必要なため、.Include()
次のようにこれらのサブエンティティを同時にロードするために使用しています。
db.MyEntities
.Where(x => x.ClientId == clientId)
.Where(x => ids.Contains(x.Id))
.Where(x => x.SubEntity1 != null)
.Include(x => x.SubEntity1)
.Include(x => x.SubEntity1.SubSubEntity1)
.Include(x => x.SubEntity1.SubSubEntity2)
.Include(x => x.SubEntity1.SubSubEntity3)
.Include(x => x.SubEntity1.SubSubEntity4)
.Include(x => x.SubEntity2)
.Include(x => x.SubEntity2.SubSubEntity1)
.Include(x => x.SubEntity2.SubSubEntity2)
.Include(x => x.SubEntity2.SubSubEntity3)
.Include(x => x.SubEntity2.SubSubEntity4)
.Include(x => x.SubEntity3)
ご覧のとおり、これらすべての を除いて、これは特に複雑なクエリではありませんInclude
。
このために EF が生成する SQL は巨大で、約74Kbの SQL です。実行にそれほど時間はかかりませんが (通常、ID のリスト内のアイテムの数は少ないため)、EFはクエリを作成するだけで 1 秒以上かかります。つまり、クエリがデータベースに送信される前です。
を削除するIncludes
と、クエリははるかに小さくなり、全体の所要時間も大幅に短縮されますが、関連するさまざまなエンティティが一度に 1 つずつ読み込まれるため、スケーリングがうまくいきません。
EF は、データをロードするための 2 つのオプションを提供しているようです。
- 最初のクエリ中にすべてのサブエンティティを一度にロードする (
Include
上記のように使用)、または - サブエンティティを一度に 1 つずつ読み込みます (遅延読み込みを使用するか、明示的に
Load
/を使用しLoadProperty
ます)。
オプション 1 が機能する場合、私の好みのオプションになりますが、この場合は機能しないため、残りのオプションは 2 だけです。これは受け入れられないと思います。データベースクエリが多すぎて、入力リストID (エンティティの数) が大きい。
EFが対処していないように見える別のオプションがあるように思えます:メインエンティティをフェッチし、関連するすべてのSubEntity1エンティティをフェッチし、次に関連するすべてのSubEntity2エンティティをフェッチするなどです。そのようにして、クエリの数はエンティティの数ではなく、フェッチされるエンティティのタイプの数。これにより、スケーリングが大幅に向上します。
EF でそれを行う方法がわかりません。つまり、「これらすべてのエンティティに対してこのプロパティを (1 つのクエリで) ロードする」ということです。
EF をあきらめて、独自の SQL を作成する必要がありますか?
更新Include
s を削除しても、生成された SQL は思ったよりも複雑である
ことに気付きました。これはすべて、EF が私のテーブル構造を「好き」ではないという事実に起因すると思います。Code First (および Fluent API) を介して探していたデータベース構造を EF で作成するのに何日も苦労しました。
私は今、EF が私に望んでいないことを大胆に行ったことに対して、さらなるペナルティを支払っていると思います。単純なクエリが必要以上に複雑であり、やや複雑なクエリが非常に複雑であるように見えます。
これは非常に気のめいることです。私は EF の面倒な作業をすべて置き去りにしたと思っていました。システムは現在、何十人ものユーザーで運用されているため、最初からやり直すのは非常に困難です。
私は永遠に EF とあらゆる場面で徹底的に戦わなければならないようです。そもそも使わなかったらよかったのに!
とにかく、元の質問に戻ります: タイプ B の関連するサブエンティティを1 つのクエリでロードしたいタイプ A のエンティティがたくさんある場合、それを行う方法はありますか?