エンティティフレームワーク-ライフサイクル
一生
コンテキストの存続期間は、インスタンスが作成されたときに始まり、インスタンスが破棄またはガベージコレクションされたときに終了します。
コンテキストの存続期間は、ORMを使用するときに行う非常に重要な決定です。
コンテキストはエンティティキャッシュのように実行されているため、ロードされたすべてのエンティティへの参照を保持しているため、メモリ消費が非常に速くなり、メモリリークが発生する可能性があります。
次の図では、コンテキストを介したアプリケーションからデータベースへの、またはその逆のデータワークフローの上位レベルを確認できます。
エンティティのライフサイクル
エンティティライフサイクルは、エンティティが作成、追加、変更、削除されるなどのプロセスを表します。エンティティには、その存続期間中に多くの状態があります。エンティティの状態を取得する方法を確認する前に、エンティティの状態とは何かを見てみましょう。状態はタイプの列挙型ですSystem.Data.EntityState 次の値を宣言します-
Added: エンティティは追加済みとしてマークされます。
Deleted: エンティティは削除済みとしてマークされます。
Modified: エンティティが変更されました。
Unchanged: エンティティは変更されていません。
Detached: エンティティは追跡されません。
エンティティライフサイクルの状態変化
エンティティの状態はコンテキストによって自動的に設定される場合がありますが、開発者が手動で変更することもできます。ある状態から別の状態への切り替えのすべての組み合わせが可能ですが、それらのいくつかは無意味です。例えば、Added エンティティ Deleted 状態、またはその逆。
さまざまな状態について話し合いましょう。
変更されていない状態
エンティティが変更されていない場合、そのエンティティはコンテキストにバインドされていますが、変更されていません。
デフォルトでは、データベースから取得されたエンティティはこの状態です。
エンティティが(Attachメソッドを使用して)コンテキストにアタッチされると、同様にUnchanged状態になります。
コンテキストは、参照していないオブジェクトへの変更を追跡できないため、オブジェクトがアタッチされると、変更されていないと見なされます。
分離状態
コンテキストはコード内のオブジェクトの作成を追跡できないため、デタッチは新しく作成されたエンティティのデフォルトの状態です。
これは、コンテキストのusingブロック内でエンティティをインスタンス化する場合でも当てはまります。
Detachedは、追跡が無効になっているときにデータベースから取得されたエンティティの状態ですらあります。
エンティティがデタッチされると、コンテキストにバインドされないため、その状態は追跡されません。
廃棄、変更、他のクラスとの組み合わせでの使用、またはその他の必要な方法での使用が可能です。
それを追跡するコンテキストがないため、EntityFrameworkにとって意味がありません。
追加された状態
エンティティが追加状態の場合、いくつかのオプションがあります。実際、コンテキストから切り離すことができるだけです。
当然、一部のプロパティを変更しても、Modified、Unchanged、またはDeletedに移動しても意味がないため、状態は追加されたままになります。
これは新しいエンティティであり、データベースの行とは対応していません。
これは、これらの状態の1つになるための基本的な前提条件です(ただし、このルールはコンテキストによって強制されません)。
変更された状態
エンティティが変更されると、それは変更されていない状態にあり、その後、一部のプロパティが変更されたことを意味します。
エンティティがModified状態に入ると、DetachedまたはDeleted状態に移行できますが、元の値を手動で復元しても、Unchanged状態にロールバックすることはできません。
このIDの行はデータベースにすでに存在し、永続化するとランタイム例外が発生するため、エンティティをデタッチしてコンテキストに追加しない限り、[追加]に変更することもできません。
削除された状態
エンティティは、UnchangedまたはModifiedであり、DeleteObjectメソッドが使用されたため、Deleted状態になります。
これは最も制限の厳しい状態です。これは、この状態から分離された以外の値に変更しても意味がないためです。
ザ・ 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フォームを使用する場合は、フォームごとにコンテキストインスタンスを使用してください。これにより、コンテキストが提供する変更追跡機能を使用できます。
経験則
Web Applications
現在、Webアプリケーションの場合、リクエストごとにコンテキストが使用されることが一般的でベストプラクティスです。
Webアプリケーションでは、非常に短いリクエストを処理しますが、すべてのサーバートランザクションを保持するため、コンテキストが存在するのに適切な期間です。
Desktop Applications
Win Forms / WPFなどのデスクトップアプリケーションの場合、コンテキストはフォーム/ダイアログ/ページごとに使用されます。
アプリケーションのシングルトンとしてコンテキストを持ちたくないので、あるフォームから別のフォームに移動するときにコンテキストを破棄します。
このようにして、コンテキストの多くの機能を取得し、長時間実行されるコンテキストの影響に悩まされることはありません。