2

クエリ/フィルタリングの前に、ナビゲーションプロパティに指定された外部キーを使用してすべてのアイテムをロードすることは、エンティティフレームワークの正しい動作ですか?

例えば:

myUser.Apples.First(a => a.Id == 1 && !a.Expires.HasValue);

そのユーザーに関連付けられているすべてのリンゴをロードします。(SQLクエリはIDまたはExpiresフィールドをクエリしません)。

これを行うには他に2つの方法があります(正しいSQLを生成します)が、ナビゲーションプロパティを使用するほどクリーンではありません。

myDbContext.Entry(myUser).Collection(u => u.Apples).Query().First(a => a.Id == 1 && !a.Expires.HasValue);

myDbContext.Apples.First(a => a.UserId == myUser.Id && a.Id == 1 && !a.Expires.HasValue);

私がチェックしたこと

  • 遅延読み込みは有効になっており、どこでも無効にされていません。
  • ナビゲーションプロパティはvirtualです。
4

1 に答える 1

2

編集:

あなたの編集に基づいて、私はあなたが何を求めているのかについて間違った考えを持っていたと思います(これは今でははるかに理にかなっています)。おそらく説明するのに役立つと思うので、前の答えを残しておきますが、現状では特定の質問との関連性ははるかに低くなります。

投稿した内容から、ユーザーオブジェクトは遅延読み込みが有効になります。EFはデフォルトで遅延読み込みを有効にしますが、遅延読み込みには、ナビゲーションプロパティを仮想としてマークするという1つの要件があります(これは実行済みです)。

遅延読み込みは、ナビゲーションプロパティのgetメソッドにアタッチし、その時点でSQLクエリを実行して、外部エンティティを取得することで機能します。ナビゲーションプロパティもクエリ可能なコレクションではありません。つまり、getメソッドを実行すると、クエリがすぐに実行されます。

上記の例では、.first呼び出しを実行する前にUserのapplesコレクションが列挙されています(これは、オブジェクトに対するプレーンな古いlinqを使用して発生します)。これは、SQLがユーザーに関連付けられているすべてのリンゴを返し、クエリを実行しているマシンのメモリでそれらをフィルタリングすることを意味します(これまで見てきたように)。これは、関心のあるリンゴをプルダウンするために2つのクエリ(1つはユーザー用、もう1つはnavプロパティ用)が必要であることも意味します。これは、必要なのがリンゴだけの場合は効率的ではない可能性があります。

これを行うためのおそらくより良い方法は、式全体をクエリとしてできるだけ長く保持することです。この例は、次のようになります。

myDbContext.Users
   .Where(u=>u.Id == userId)
   .SelectMany(u=>u.Apples)
   .Where(a=>a.Id == 1 && !a.Expires.HasValue);

これは単一のSQLステートメントとして実行し、気になるリンゴだけをプルダウンする必要があります。

HTH


私があなたの質問を理解できることから、あなたは、EFが結果セットでヌルである可能性があるにもかかわらず、クエリでナビゲーションプロパティを使用できるように見える理由を尋ねています。

はい、あなたの質問に答えて、これは予想される動作です。理由は次のとおりです。

クエリを作成する理由は、SQLに変換されます。たとえば、次のようになります。

myDbContext.Apples.Where(a=>a.IsRed)

のようなものに変わります

Select * from Apples
where [IsRed] = 1

同様に、次のようなものもSQLに直接変換されます

myDbContext.Apples.Where(a=>a.Tree.Height > 100)

のようなものに変わります

Select a.* from Apples as a
inner join Tree as t on a.TreeId = t.Id
where t.Height > 100

ただし、実際に結果セットをプルダウンすると、話は少し異なります。

大量のデータをプルダウンして遅くすることを避けるために、EFは、結果セットに何が返されるかを指定するためのいくつかのメカニズムを提供します。1つは遅延読み込み(パフォーマンスの問題を回避したい場合は注意深く使用する必要があります)で、もう1つはinclude構文です。これらのメソッドは、クエリが迅速に行われ、不要なリソースを消費しないように、プルバックするものを制限します。

たとえば、上記では、Appleフィールドのみが返されることに注意してください。

以下のようにインクルードを追加すると、異なる結果が得られる可能性があります。

myDbContext.Apples.Include(a=>a.Tree).Where(a=>a.Tree.Height > 100)

次のようなSQLに変換されます。

Select a.*, t.* from Apples as a
inner join Tree as t on a.TreeId = t.Id
where t.Height > 100

上記の例(myContext.Usersはコレクションである必要があるため、.Applesを持たない必要があるため、構文的に正しくないと確信しています)では、すべての変数が使用可能であるためのクエリを作成しています。そのクエリを列挙するときは、何が返されるかを明示する必要があります。

ナビゲーションプロパティとその機能(および.Include構文)の詳細については、私のブログをチェックしてください:http: //blog.staticvoid.co.nz/2012/07/entity-framework-navigation-property.html

于 2012-11-27T07:23:21.023 に答える