web-dev-qa-db-ja.com

リストにEntity Frameworkの別のリストのアイテムが含まれているかどうかを確認します

関連付けられた場所のリストを持つエンティティPersonがあります。個人テーブルを照会し、ロケーションのリスト(基準)から少なくとも1つのロケーションを持つすべてのユーザーを取得する必要があります。以下は機能しますが、非常に非効率的です。

var searchIds = new List<int>{1,2,3,4,5};
var result = persons.Where(p => p.Locations.Any(l => searchIds.Any(id => l.Id == id)));

これは、小さなリスト(たとえば、5〜10のsearchIdと5〜10のロケーションを持つ人)で問題なく動作します。 EFは実際に2000以上のSQLステートメントを生成し、ネストが深すぎたために失敗しました。ネスティング自体は既に問題になっていますが、それが機能する場合でも、2000以上のSQLステートメントではあまり起こりません。

注:実際のコードには複数のレベルと親子関係も含まれていますが、完全なオブジェクトではなく、idのみを使用して、このかなりフラットな構造にまとめることができました

EFでこれを達成する最良の方法は何でしょうか?

27
Kenneth

提案します:

var searchIds = new List<int>{1,2,3,4,5};
var result = persons.Where(p => p.Locations.Any(l => searchIds.Contains(l.Id)));

ContainsINステートメントに変換されます。

IDリストはsqlステートメントに含まれることに注意してください。 IDリストが巨大な場合、膨大なクエリが発生します。

57
Ivo

次のような大量のデータを実行する代わりに、結合に切り替えてみてください。

var searchIds = new List<int>{1,2,3,4,5};
var results = (from p in persons
               join l in Location on p.PersonId equals l.PersonId
               where searchIds.Contains(l.Id)
               select p).Distinct().ToList();

明らかにこの行を修正して、クラスや結合プロパティに合わせてください。

join l in Location on p.PersonId equals l.PersonId

私はそれがより友好的な実行計画を生成することを期待しています。

6
Timeout