Entity-framework-lifecycle
提供:Dev Guides
Entity Framework-ライフサイクル
一生
コンテキストのライフタイムは、インスタンスが作成されたときに始まり、インスタンスが破棄されるかガベージコレクションされると終了します。
- コンテキストの有効期間は、ORMを使用するときに行う非常に重要な決定です。
- コンテキストはエンティティキャッシュのように機能するため、メモリ消費が非常に速くなる可能性のあるロードされたすべてのエンティティへの参照を保持し、メモリリークを引き起こす可能性もあります。
- 次の図では、コンテキストを介したアプリケーションからデータベースへ、またはその逆のデータワークフローの上位レベルを見ることができます。
エンティティのライフサイクル
エンティティライフサイクルは、エンティティが作成、追加、変更、削除などされるプロセスを記述します。 エンティティには、その存続期間中に多くの状態があります。 エンティティ状態を取得する方法を見る前に、エンティティ状態とは何かを見てみましょう。 状態は、次の値を宣言する System.Data.EntityState 型の列挙型です-
- *追加:*エンティティは追加済みとしてマークされます。
- *削除済み:*エンティティは削除済みとしてマークされます。
- *変更済み:*エンティティが変更されました。
- *変更なし:*エンティティは変更されていません。
- *分離:*エンティティは追跡されません。
エンティティライフサイクルの状態変更
エンティティの状態はコンテキストによって自動的に設定されることもありますが、開発者が手動で変更することもできます。 ある状態から別の状態へのスイッチのすべての組み合わせは可能ですが、それらのいくつかは無意味です。 たとえば、 Added エンティティを Deleted 状態に、またはその逆に。
さまざまな州について議論しましょう。
変更されていない状態
- エンティティが変更されていない場合、そのエンティティはコンテキストにバインドされていますが、変更されていません。
- デフォルトでは、データベースから取得されたエンティティはこの状態です。
- エンティティが(Attachメソッドを使用して)コンテキストにアタッチされると、同様にUnchanged状態になります。
- コンテキストは、参照していないオブジェクトへの変更を追跡できないため、添付された場合、変更されていないものと見なされます。
分離状態
- コンテキストはコード内のオブジェクトの作成を追跡できないため、新しく作成されたエンティティのデフォルトの状態はDetachedです。
- これは、コンテキストのusingブロック内でエンティティをインスタンス化する場合でも当てはまります。
- 分離は、追跡が無効になっているときにデータベースから取得されたエンティティの状態です。
- エンティティが切り離されると、そのエンティティはコンテキストにバインドされないため、その状態は追跡されません。
- 破棄、変更、他のクラスと組み合わせて使用、または必要に応じて他の方法で使用できます。
- それを追跡するコンテキストがないため、Entity Frameworkには意味がありません。
追加された状態
- エンティティが追加状態の場合、選択肢はほとんどありません。 実際、コンテキストからのみデタッチできます。
- 当然、一部のプロパティを変更しても、Modified、Unchanged、またはDeletedに移動しても意味がないため、状態は追加のままです。
- これは新しいエンティティであり、データベース内の行とは対応していません。
- これは、これらの州のいずれかにいるための基本的な前提条件です(ただし、このルールはコンテキストによって強制されません)。
変更された状態
- エンティティが変更されると、そのエンティティは変更されていない状態になり、一部のプロパティが変更されたことを意味します。
- エンティティが変更状態になると、エンティティは切り離された状態または削除された状態に移行できますが、元の値を手動で復元しても、変更されていない状態にロールバックすることはできません。
- エンティティをデタッチしてコンテキストに追加しない限り、このIDの行はデータベースに既に存在し、永続化すると実行時例外が発生するため、追加に変更することさえできません。
削除された状態
- エンティティは、UnchangedまたはModifiedであるためDeleted状態になり、DeleteObjectメソッドが使用されました。
- これは、この状態からDetached以外の値に無意味に変化するため、最も制限的な状態です。
コンテキストが制御するすべてのリソースをブロックの最後に配置する場合は、 using ステートメント。 using ステートメントを使用すると、コンパイラーは自動的にtry/finallyブロックを作成し、finallyブロックでdisposeを呼び出します。
using (var context = new UniContext()) {
var student = new Student {
LastName = "Khan",
FirstMidName = "Ali",
EnrollmentDate = DateTime.Parse("2005-09-01")
};
context.Students.Add(student);
context.SaveChanges();
}
長期実行コンテキストで作業する場合は、次のことを考慮してください-
- より多くのオブジェクトとその参照をメモリにロードすると、コンテキストのメモリ消費が急速に増加する場合があります。 これにより、パフォーマンスの問題が発生する可能性があります。
- 不要になったコンテキストは必ず破棄してください。
- 例外によってコンテキストが回復不能な状態になると、アプリケーション全体が終了する場合があります。
- データのクエリと更新の時間のギャップが大きくなると、同時実行に関連する問題が発生する可能性が高くなります。
- Webアプリケーションを使用する場合、リクエストごとにコンテキストインスタンスを使用します。
- Windows Presentation Foundation(WPF)またはWindows Formsを使用する場合、フォームごとにコンテキストインスタンスを使用します。 これにより、コンテキストが提供する変更追跡機能を使用できます。
経験則
ウェブアプリケーション
- 現在、Webアプリケーションでは、リクエストごとにコンテキストが使用されるのが一般的でベストプラクティスです。
- Webアプリケーションでは、非常に短いリクエストを処理しますが、すべてのサーバートランザクションを保持するため、コンテキストが存在する適切な期間です。
デスクトップアプリケーション
- Win Forms/WPFなどのデスクトップアプリケーションの場合 コンテキストは、フォーム/ダイアログ/ページごとに使用されます。
- アプリケーションのシングルトンとしてコンテキストを持ちたくないので、あるフォームから別のフォームに移動するときにそれを破棄します。
- このようにして、コンテキストの多くの能力を獲得し、長時間実行されるコンテキストの影響を受けなくなります。