ID 解決、状態管理、および変更の追跡 (Entity Framework)
ObjectContext は、メモリ内オブジェクトのコンテナーを表します。 オブジェクト コンテキストは、他のクラスやインターフェイスと連携して、オブジェクトの ID、状態、オブジェクトのプロパティの元の値と現在の値を管理し、キャッシュ内の各オブジェクトに対して行われた変更を追跡します。 オブジェクト コンテキストにオブジェクトをアタッチする方法については、「オブジェクトのアタッチとデタッチ (Entity Framework)」を参照してください。 ここでは、変更追跡、ID 解決、および状態管理がオブジェクト コンテキストでどのように行われるかについて説明します。
変更の追跡
オブジェクト グラフの変更追跡情報は、アタッチされている各オブジェクトについて ObjectContext が作成する ObjectStateEntry オブジェクトに格納されます。 ObjectStateEntry オブジェクトには、エンティティに関して次の情報が格納されます。
-
エンティティの ID を決定する EntityKey。
オブジェクトの EntityState。
関連するオブジェクトの情報。
エンティティ セットの名前。
エンティティのプロパティの CurrentValues と OriginalValues (Added 状態のオブジェクトには元の値は存在しません)。
エンティティの変更済みプロパティの名前。
SaveChanges の呼び出しの間に、プロパティの値が変更されたかどうかを調べるには、GetModifiedProperties メソッドによって返される変更されたプロパティ名のコレクションを照会します。
注 : |
---|
変更追跡プロキシを持たない POCO エンティティを使用する場合は、GetModifiedProperties を呼び出す前に、DetectChanges を呼び出す必要があります。 |
エンティティがデタッチされると、対応する ObjectStateEntry オブジェクトがオブジェクト コンテキストから削除されます。
ObjectStateEntry オブジェクトは ObjectStateManager によって管理されます。 各オブジェクト コンテキストについて、ObjectStateManager のインスタンスが 1 つ存在します。 指定したエンティティの ObjectStateEntry オブジェクトを取得するには、ObjectStateManager の TryGetObjectStateEntry、GetObjectStateEntry、GetObjectStateEntries のいずれかのメソッドを使用します。
オブジェクト コンテキストは、Entity Framework によって生成されたエンティティのプロパティおよび POCO 変更追跡プロキシ オブジェクトのプロパティが変更されると通知を受け取り、ObjectStateEntry 内のオブジェクトの状態とプロパティの値を更新します。 変更報告モデルでは、プロパティの保留中の変更の報告、プロパティの設定、および変更が完了したことの報告が IEntityChangeTracker インターフェイスを使用して行われます。 ObjectStateEntry は、変更追跡プロキシ オブジェクトおよび複合型オブジェクトを含まない POCO エンティティを異なる方法で管理します。 詳細については、「POCO エンティティでの変更の追跡 (Entity Framework)」を参照してください。
オブジェクト コンテキストは、ObjectStateEntry オブジェクト内の情報を使用して、データ ソースにデータを永続化します。 詳細については、「変更の保存と同時実行制御の管理 (Entity Framework)」および「変更を保存するときにビジネス ロジックを実行する方法 (Entity Framework)」を参照してください。
ID 解決およびマージ オプション
Entity Framework では、特定のエンティティ キーを持つオブジェクトの 1 つのみのインスタンスをキャッシュ内に保持します。 EntityKey オブジェクトは、オブジェクトの ID を表す不変のオブジェクトです。 エンティティ キーは、オブジェクト コンテキスト内の ID 解決を実行するために使用されます。 詳細については、「エンティティ キーの使用 (Entity Framework)」を参照してください。 同じ ID を持つエンティティが既に追跡されている場合、データ ソースからのデータと状態マネージャーに既に存在するデータは、クエリの MergeOption に従ってマージされます。
次の表は、使用できるマージ オプションを示しています。
メンバー | 説明 |
---|---|
オブジェクト コンテキストに存在しないオブジェクトは、コンテキストにアタッチされます。 オブジェクトが既にコンテキストに存在する場合、エントリに格納されているオブジェクトのプロパティの現在の値と元の値が、データ ソースの値で上書きされることはありません。 オブジェクトのエントリの状態と、エントリ内にあるオブジェクトのプロパティの状態は変化しません。 AppendOnly は既定のマージ オプションです。 |
|
オブジェクト コンテキストに存在しないオブジェクトは、コンテキストにアタッチされます。 オブジェクトが既にコンテキストに存在する場合、エントリに格納されているオブジェクトのプロパティの現在の値と元の値が、データ ソースの値で上書きされます。 オブジェクトのエントリの状態は Unchanged に設定され、いずれのプロパティも変更済みとしてマークされません。 |
|
オブジェクト コンテキストに存在しないオブジェクトは、コンテキストにアタッチされます。 エンティティの状態が Unchanged の場合、エントリに格納されている現在の値と元の値が、データ ソースの値で上書きされます。 エントリの状態は Unchanged のままとなり、いずれのプロパティも変更済みとしてマークされません。 エンティティの状態が Modified の場合、変更されているプロパティの現在の値は、データ ソースの値で上書きされません。 変更されていないプロパティの元の値は、データ ソースからの値で上書きされます。 .NET Framework バージョン 4 では、変更されていないプロパティの現在の値とデータ ソースから返された値とが Entity Framework によって比較されます。 両者の値が異なる場合、プロパティは変更済みとしてマークされます。 .NET Framework バージョン 3.5 SP1 では、データ ソースの値が異なっていたとしても、Entity Framework によってプロパティが変更済みとしてマークされることはありません。 変更されているプロパティだけが、SaveChanges を呼び出したときにデータ ソースに永続化されます。 3.5 SP1 の動作を保持するには、UseLegacyPreserveChangesBehavior を true に設定します。 PreserveChanges オプションは、ローカル コンテキストで変更を保持しながら、オプティミスティック同時実行例外を解決するために使用できます。 詳細については、「変更の保存と同時実行制御の管理 (Entity Framework)」を参照してください。 |
|
オブジェクトは、Detached 状態で保持され、ObjectStateManager では追跡されません。 ただし、Entity Framework により生成されたエンティティおよびプロキシを持つ POCO エンティティは、関連するオブジェクトの読み込みを容易にするために、オブジェクト コンテキストへの参照を保持します。 |
エンティティ状態
オブジェクト コンテキストは、データ ソースに変更を保存し直すために、オブジェクトの状態を認識している必要があります。 ObjectStateEntry オブジェクトは EntityState 情報を格納します。 ObjectContext の SaveChanges メソッドは、コンテキストにアタッチされているエンティティを処理し、各オブジェクトの EntityState に応じてデータ ソースを更新します。 詳細については、「オブジェクトの作成、追加、変更、および削除 (Entity Framework)」を参照してください。 次の表は、オブジェクトの考えられる状態を示しています。
メンバー | 説明 |
---|---|
Added |
新しいオブジェクトがオブジェクト コンテキストに追加されています。SaveChanges メソッドは呼び出されていません。 変更が保存されると、オブジェクトの状態は Unchanged に変更されます。 Added 状態にあるオブジェクトは、ObjectStateEntry に元の値を保持していません。 |
オブジェクトは、オブジェクト コンテキストから削除されています。 変更が保存されると、オブジェクトの状態は Detached に変更されます。 |
|
Detached |
オブジェクトが存在しますが追跡されていません。 エンティティは、作成された直後とオブジェクト コンテキストに追加される直前にこの状態になります。 また、Detach メソッドを呼び出してコンテキストから削除された後、または NoTracking MergeOption を使用して読み込まれる場合にもこの状態になります。 Detached 状態のオブジェクトに関連付けられた ObjectStateEntry インスタンスは存在しません。 |
Modified |
オブジェクトのスカラー プロパティのいずれかが変更されています。SaveChanges メソッドは呼び出されていません。 変更追跡プロキシを持たない POCO エンティティでは、DetectChanges メソッドが呼び出されたときに、変更されているプロパティの状態が Modified に変わります。 変更が保存されると、オブジェクトの状態は Unchanged に変更されます。 |
Unchanged |
オブジェクトは、コンテキストにアタッチされた後、または最後に SaveChanges メソッドが呼び出されてから変更されていません。 |
オブジェクト コンテキスト内のオブジェクトの状態は、ObjectStateManager で管理されます。 オブジェクトの状態を確認するには、ObjectStateManager メソッドである、TryGetObjectStateEntry、GetObjectStateEntry、または GetObjectStateEntries のいずれかを呼び出します。 ObjectStateEntry の State プロパティが、オブジェクトの状態を定義します。