3

これは、LINQPad で遊んでみたことに基づく私の仮定に沿ったコードです。これが遅延読み込みの仕組みであることを誰でも確認できますか?バックエンドでの動作を理解できるように、追加の洞察/リンクを提供してください。前もって感謝します!

// Step 1.
var record = context.MyTable.First();

// Step 2.
var foreignKey = ForeignKeyTable.Where(x => x.Id == record.ForeignKeyId).Single();

// Step 3.
var entry = context.Entry(record);

// Step 4.
trace(entry.Reference(x => x.ForeignKey).IsLoaded);

// Step 5.
trace(record.ForeignKey.SomeProperty);
  1. いくつかのレコードを取得します (DB が照会されます)。
  2. たまたま の外部キー プロパティであるレコードを取得するrecordように遅延読み込みを使用せずrecord.ForeignKeyに取得します (DB がクエリされます)。
  3. recordエンティティの詳細を取得します。
  4. これは私が確信していない部分です。私のテストでは、出力されますtrue。IsLoaded はrecord.ForeignKey、現在値があるかどうかを認識していませんが、そのrecord.ForeignKey知識と確立された関係に基づいて、コンテキストで既に追跡されていることを認識しrecord.ForeignKeyIdていると思います。
  5. db はここではヒットしていないようです。同じ理由IsLoadedで 4 で true が返されると思います。foreignKey既にオブジェクトを追跡していることを認識しているため、遅延読み込みを行う必要がないことを認識しています。

編集:私が解決しようとしている実際の問題は、次のように説明できます。

var record = context.MyTable.First();

var foreignKey = new ForeignKey() { Id = record.ForeignKeyId, SomeProperty = 5 };
context.ForeignKeyTable.Attach(foreignKey);

var entry = context.Entry(record);

// Returns false.
trace(entry.Reference(x => x.ForeignKey).IsLoaded);

// Doesn't query for ForeignKey, so it must know it's `loaded` somehow, and
// gets SomeProperty from my new foreignKey object. What???
trace(record.ForeignKey.SomeProperty);
4

2 に答える 2

2

EF は、データベースからエンティティを読み込むとき、またはエンティティをコンテキストにアタッチするときに、主キーと外部キーの値に従って自動的にリレーションシップ (ナビゲーション プロパティ) を修正します。

ロードした両方のコード スニペットrecordで、ForeignKeyTable. コンテキストはこの値を知っています。(モデルで外部キーを公開しているかどうかは関係ありません。モデルに FK プロパティがなくても、常にロードされます。これは、SQL クエリを見るとわかります。)

どちらの場合も、コンテキストがすでに知っているForeignKey値を主キーとして持つエンティティを後でコンテキストにアタッチします。record.ForeignKeyId結果として、EF はナビゲーション プロパティrecord.ForeignKeyをこの添付ForeignKeyエンティティに設定します。

エンティティがコンテキストにアタッチされているかどうかは明らかにわかりIsLoadedません。両方の例でアタッチされていますが、一方が返さtrueれ、もう一方が返されるためfalseです。また、エンティティを参照しているかどうかもわかりませんrecord.ForeignKeyId。これは両方の例に当てはまるためです。

明らかに、エンティティがデータベースから実際にロードされたことのみを示します (手動でアタッチされただけではありません) (Intellisense は についても述べていますIsLoaded)。それが最初と2番目の例の唯一の違いです。

IsLoadedそして、遅延読み込みはフラグによって制御されるだけではないようです。ナビゲーション プロパティのエンティティをコンテキストにアタッチするとIsLoadedfalse.

2 番目のコード スニペットの最後の行が実際に遅延読み込みをトリガーするとどうなるでしょうか? 読み込まれるオブジェクトには、既にアタッチForeignKeyされているオブジェクトと同じキーが必要です (この値が FK プロパティとしてあるため)。ただし、同じキーを持つ 2 つのオブジェクトをコンテキストに関連付けることはできないため、同じオブジェクトでなければなりません。ただし、そのようなオブジェクトはすでにメモリ内にあり、アタッチされているため、ロードする必要はありません。ForeignKeyrecordForeignKeyId

于 2011-12-15T21:30:16.340 に答える
1
// Step 1.
var record = context.MyTable.First();

// Step 2.
var foreignKey = ForeignKeyTable.Where(x => x.Id == record.ForeignKeyId).Single();

// Step 3.
var entry = context.Entry(record);

// Step 4.
trace(entry.Reference(x => x.ForeignKey).IsLoaded);

// Step 5.
trace(record.ForeignKey.SomeProperty);
  1. いくつかのレコードを取得します (DB が照会されます)。はい、結果のレコードは DbContext にアタッチされます。
  2. record.ForeignKey のような遅延読み込みを使用せずに、レコードの外部キー プロパティであるレコードを取得します (DB がクエリされます)。はい。#1 で外部キーを積極的にロードしたい場合は、context.MyTable.Include(m => m.ForeignKey).First(); を使用します。これにより、1 つのクエリで fk と共にレコードが取得されます。
  3. レコード エンティティの詳細を取得します。種類... DbContextに関連するエンティティの詳細です(アタッチ/削除/ロード/など)
  4. これは私が確信していない部分です。私のテストでは、true が出力されます。IsLoaded は、record.ForeignKey が現在値を持っているかどうかを認識していませんが、record.ForeignKeyId の知識と確立された関係に基づいて、record.ForeignKey が既にコンテキストで追跡されていることを認識していると思います。これは、DbContext が外部キーのデータを読み込むために別のクエリを実行する必要がないことを意味します。record.ForeignKey を実行すると、データはすでにそこにあるため、データベースへの追加のトリップは必要ありません
  5. db はここではヒットしていないようです。IsLoaded が 4 で true を返すのと同じ理由だと思います。それは、foreignKey オブジェクトを既に追跡していることを知っているので、遅延読み込みを行う必要がないことを知っています。エンティティはステップ 2 ですでにロードされているため、データベースから取得するために追加のトリップは必要ありませんでした。

質問編集後の更新

EF によると、IDbSet の .Attach メソッド:

指定されたエンティティをセットの基になるコンテキストにアタッチします。つまり、エンティティは、あたかもデータベースから読み取られたかのように、Unchanged 状態でコンテキストに配置されます。

于 2011-12-15T20:05:43.220 に答える