1. ホーム
  2. .net

[解決済み】Entity Frameworkと接続プーリング

2022-04-01 22:17:49

質問

最近、.NET 4.0アプリケーションでEntity Framework 4.0を使い始めましたが、プーリングに関連するいくつかの事柄に興味を持っています。

  1. 接続プーリングは、ADO.NETデータプロバイダ(私の場合はMS SQL Server)によって管理されています。これは、新しいエンティティ・コンテキスト( ObjectContext )、すなわち、パラメータなしの new MyDatabaseModelEntities() ?

  2. a) アプリケーションのグローバルなエンティティコンテキストを作成する(つまり、1つの静的インスタンス)、または b) 特定の操作/メソッドごとにエンティティコンテキストを作成し公開し、そのコンテキストに using ブロックを作成します。

  3. その他、推奨事項、ベストプラクティス、特定のシナリオに対する一般的なアプローチなど、知っておくべきことがあれば教えてください。

解決方法は?

  1. 接続プーリングは、他のADO.NETアプリケーションと同様に処理されます。エンティティ接続は、従来のデータベース接続と従来の接続文字列を使用します。接続プーリングを使用しない場合は、接続文字列で接続プーリングをオフにすることができると思います。(詳しくは SQL Server 接続プーリング (ADO.NET) )
  2. グローバルコンテキストは絶対に使わないでください。ObjectContextは内部でIdentity MapやUnit of Workなどいくつかのパターンを実装しています。グローバルコンテキストを使用した場合の影響は、アプリケーションの種類によって異なる。
  3. ウェブアプリケーションでは、リクエストごとに単一のコンテキストを使用します。Webサービスでは、呼び出しごとに1つのコンテキストを使用します。WinFormsやWPFアプリケーションでは、フォームまたはプレゼンターごとに単一のコンテキストを使用します。この方法を使用できない特別な要件がある場合もありますが、 ほとんどの場合、これで十分です。

WPF / WinFormアプリケーションのシングルオブジェクトコンテキストがどのような影響を与えるか知りたい場合は、こちらをご覧ください。 記事 . これはNHibernateセッションに関するものですが、考え方は同じです。

編集する

EFを使用する場合、デフォルトでは各コンテキストにつき1回だけ各エンティティをロードします。最初のクエリは、エンティティのインスタンスを作成し、それを内部に格納します。同じキーを持つエンティティを必要とする後続のクエリは、この保存されたインスタンスを返します。データストアの値が変更された場合でも、最初のクエリの値を持つエンティティを受け取ります。これは Identity mapパターン . オブジェクトコンテキストで強制的にエンティティを再読み込みすることはできますが、単一の共有インスタンスを再読み込みすることになります。

を呼び出すまで、エンティティに加えられたすべての変更は永続化されません。 SaveChanges をコンテキストに追加します。複数のエンティティで変更を行い、それらを一度に保存することができます。これは ユニットオブワークパターン . 変更された添付エンティティを選択的に保存することはできません。

この2つのパターンを組み合わせると、面白い効果が見えてきます。アプリケーション全体に対して、エンティティのインスタンスは1つしかありません。たとえ変更が永続化(コミット)されていなくても、エンティティへの変更はすべてアプリケーション全体に影響します。ほとんどの場合、これはあなたが望むことではありません。例えば、WPFアプリケーションに編集フォームがあるとします。エンティティを操作しているときに、複雑な編集(値の変更、関連エンティティの追加、他の関連エンティティの削除など)をキャンセルすることを決定します。しかし、そのエンティティはすでに共有コンテキストで変更されています。あなたはどうしますか?ヒント: 私は ObjectContext .

サーバーのシナリオについては説明するまでもないでしょう。複数のHTTPリクエストやWebサービスの呼び出しの中で、単一のエンティティを共有するだけでは、アプリケーションの意味がありません。どのようなリクエストでも SaveChanges というのも、1つの作業単位をすべてのリクエストで共有しているからです。これはまた別の問題でもあります。コンテキストと、コンテキスト内のエンティティやコンテキストが使用するデータベース接続に対する操作は、スレッドセーフではありません。

読み取り専用のアプリケーションの場合でも、グローバルコンテキストは良い選択ではありません。なぜなら、おそらくアプリケーションに問い合わせるたびに新鮮なデータが欲しいからです。