(1)の説明は正しいですが、これは遅延読み込みではなく、熱心な読み込みの例です。
(2)の説明が正しくありません。(2)は技術的には読み込みをまったく使用していませんが、FlaggedDatesの非スカラー値にアクセスしようとすると、遅延読み込みを使用します。
いずれの場合も、_flaggedDatesを使用して「何かを実行」しようとするまで、データストアからデータがロードされないのは正しいことです。ただし、それぞれの場合で何が起こるかは異なります。
(1):積極的な読み込み:for
ループを開始するとすぐに、指定したすべてのオブジェクトがデータベースから取得され、巨大なメモリ内データ構造に組み込まれます。これは非常にコストのかかる操作であり、データベースから膨大な量のデータを取得します。ただし、これはすべて1つのデータベースラウンドトリップで発生し、1つのSQLクエリが実行されます。
(2):遅延読み込み:for
ループが開始されると、FlaggedDatesオブジェクトのみが読み込まれます。ただし、for
ループ内の関連オブジェクトにアクセスする場合、それらのオブジェクトはまだメモリにロードされていません。特定のFlaggedDateのscheduledSchoolsを最初に取得しようとすると、学校を取得するための新しいデータベースラウンドトリップが発生するか、コンテキストが既に破棄されているために例外がスローされます。ループ内でscheduledSchoolsコレクションにアクセスするため、ループfor
の開始時に最初にロードしたFlaggedDateごとに新しいデータベースラウンドトリップが発生しfor
ます。
コメントへの返信
遅延読み込みを無効にすることは、熱心な読み込みを有効にすることと同じではありません。この例では:
context.ContextOptions.LazyLoadingEnabled = false;
var schools = context.FlaggedDates.First().scheduledSchools;
元のクエリ(FlaggedDates.First())schools
に含まれていなかったため、変数には空のEntityCollectionが含まれInclude
、最初のクエリの実行後にロードできないように遅延ロードを無効にしました。
正しいのは、where d.dateID == 2
その特定のFlaggedDateオブジェクトに関連するオブジェクトのみがプルされることを意味します。ただし、そのFlaggedDateに関連するオブジェクトの数によっては、そのワイヤを介して大量のデータが送信される可能性があります。これは、EntityFrameworkがSQLクエリを構築する方法によるものです。SQLクエリの結果は常に表形式です。つまり、すべての行に同じ数の列が必要です。すべてのscheduledSchoolオブジェクトについて、結果セットに少なくとも1つの行が必要であり、すべての行に少なくともいくつかの行が含まれている必要があるためです。すべての列の値を指定すると、FlaggedDateオブジェクトのすべてのスカラー値が繰り返されることになります。したがって、FlaggedDateに関連付けられた10個のscheduledSchoolsと10個のインタビューがある場合、それぞれがFlaggedDateのすべてのスカラー値を含む20行になります。行の半分はすべてのScheduledSchool列に対してヌル値を持ち、残りの半分はすべてのインタビュー列に対してヌル値を持ちます。
ただし、これが非常に悪くなるのは、含めるデータを「深く」する場合です。たとえば、各ScheduledSchoolにstudents
プロパティがあり、これも含めた場合、突然、各ScheduledSchoolの各Studentの行が作成され、それらの各行に、StudentのScheduledSchoolのすべてのスカラー値が含まれます(元のFlaggedDateオブジェクトのすべてのスカラー値とともに、最初の行の値のみが使用されることになります)。それはすぐに合計することができます。
書面で説明するのは難しいですが、複数のsを含むクエリから返される実際のデータInclude
を見ると、重複するデータがたくさんあることがわかります。LinqPadを使用して、EFコードによって生成されたSQLクエリを確認できます。