19

遅延読み込みなどについて混乱しています。

まず、これら2つのステートメントは同等ですか。

(1) Lazy loading:
_flaggedDates = context.FlaggedDates.Include("scheduledSchools")
.Include  ("interviews").Include("partialDayAvailableBlocks")
.Include("visit").Include("events");

(2) Eager loading:
_flaggedDates = context.FlaggedDates;

つまり、(1)で「インクルード」を使用すると、遅延読み込みを使用しているにもかかわらず、ナビゲーションコレクション/プロパティが、要求された特定のコレクションとともに読み込まれます。

また、(2)では、積極的な読み込みを使用しているため、特にリクエストしなくても、ステートメントはすべてのナビゲーションエンティティを読み込みます...そうですか?

2番目:積極的な読み込みを使用している場合でも、次のコードのように、「列挙可能なものを列挙する」まで、データは実際にはデータベースからダウンロードされません。

var dates = from d in _flaggedDates
            where d.dateID = 2
            select d;
foreach (FlaggedDate date in dates)
{
... etc.
}

foreachループが実行されるまで、データは実際にはダウンロード(「列挙」)されません...そうですか?つまり、「vardates」行はクエリを定義しますが、クエリはforeachループまで実行されません。

それを考えると(私の仮定が正しければ)、積極的な読み込みと遅延読み込みの本当の違いは何ですか?どちらの場合も、列挙するまでデータは表示されないようです。私は何かが足りないのですか?

(私の特定の経験は、コードファーストのPOCO開発ですが、質問はより一般的に当てはまるかもしれません。)

4

2 に答える 2

17

(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クエリを確認できます。

于 2010-09-16T20:34:15.747 に答える
0

変わりはない。これは、熱心な読み込みをサポートしていなかったEF 1.0では当てはまりませんでした(少なくとも自動的にはサポートされていませんでした)。1.0では、プロパティを変更して自動的にロードするか、プロパティ参照でLoad()メソッドを呼び出す必要がありました。

覚えておくべきことの1つは、次のように複数のオブジェクト間でクエリを実行すると、これらのインクルードが煙に包まれる可能性があることです。

from d in ctx.ObjectDates.Include("MyObjectProperty")
from da in d.Days

ObjectDate.MyObjectPropertyは自動的にロードされません。

于 2010-09-16T20:36:19.573 に答える