あなたの質問
私の状況で ObjectContext を共有するかしないか?
コンテキストを共有しないでください。EntityFramework コンテキストは、UnitOfWork パターンに従う必要があります。オブジェクト コンテキストは、不必要に多くのコンテキストを作成/破棄することなく、できるだけ短命にする必要があります。これは通常、作業単位としてアプリ内の個々の「操作」に変換されます。Web アプリ/API の場合、これは ごとHttpWebRequest
である場合もあれば、論理データ操作ごとに行う場合もあります (「ビジネス ロジック」の実装された部分ごとに)。
例えば:
LoadBusinssObjects()
コンテキストを作成し、データのリストと必要な関連データをロードしてから、コンテキストを破棄します。
CreateBusinessObject()
コンテキストを作成し、いくつかのエンティティのインスタンスを作成し、それにデータを入力し、コンテキスト内の収集にアタッチし、変更を保存してからコンテキストを破棄します。
UpdateBusinessObject()
コンテキストからオブジェクトを読み取り、更新し、変更を保存し、コンテキストを破棄します。
DeleteBusinessObject()
コンテキスト内でビジネス オブジェクトを検索し、コンテキスト内のコレクションから削除し、変更を保存してコンテキストを破棄します。
共有しない場合、1 つの objectContext を他の変更で更新するという現在の問題をどのように解決できますか? これは、 pub/sub アーキテクチャ
の仕事です。これは、上で実装した操作ごとに、オブジェクトにいくつかの静的イベント ハンドラーを配置するだけの簡単なものです。次に、各ビジネス オペレーションのコードで、対応するイベントを発生させます。
共有する場合 - どちらがより良い方法でしょうか? 静的かシングルトンか何か?
これは正しくありません。EF コンテキストは、コンテキストの状態マネージャーが、アプリケーションで行うすべての対話に対してキャッシュされたオブジェクト (添付されているオブジェクトと添付されていないオブジェクトの両方) を継続的に収集するため、メモリ フットプリントが増加し続けます。コンテキストは、このように機能するようには設計されていません。
リソースの使用に加えて、EF コンテキストはスレッド セーフではありません。たとえば、ツリー リストが新しいデータをロードしているときに、エディタ フォームの 1 つが変更を保存できるようにしたい場合はどうでしょうか。1 つの静的インスタンスでは、これがすべて UI スレッドで実行されているか、セマフォと同期されていることを確認することをお勧めします (yuck、yuck - 悪い習慣)。
例
あなたの投稿に従って、C#とコードファーストのアプローチを使用した例を次に示します。例を簡潔にするために、データの同時実行性やスレッド化などについては触れていないことに注意してください。また、実際のアプリケーションでは、この概念はジェネリックとリフレクションで実装されているため、すべてのモデルに作成、更新、削除の基本的なイベントがあります。
public class MyCodeFirstEntityChangedArgs : EventArgs
{
/// <summary>
/// The primary key of the entity being changed.
/// </summary>
public int Id {get;set;}
/// <summary>
/// You probably want to make this an ENUM for Added/Modified/Removed
/// </summary>
public string ChangeReason {get;set;}
}
public class MyCodeFirstEntity
{
public int Id {get;set;}
public string SomeProperty {get;set;}
/// <summary>
/// Occurs when an instance of this entity model has been changed.
/// </summary>
public static event EventHandler<MyCodeFirstEntityChangedArgs> EntityChanged;
}
public class MyBusinessLogic
{
public static void UpdateMyCodeFirstEntity(int entityId, MyCodeFirstEntity newEntityData)
{
using(var context = new MyEFContext())
{
// Find the existing record in the database
var existingRecord = context.MyCodeFirstEntityDbSet.Find(entityId);
// Copy over some changes (in real life we have a
// generic reflection based object copying method)
existingRecord.Name = newEntityData.Name;
// Save our changes via EF
context.SaveChanges();
// Fire our event handler so that other UI components
// subscribed to this event know to refresh/update their views.
// ----
// NOTE: If SaveChanges() threw an exception, you won't get here.
MyCodeFirstEntity.EntityChanged(null, new MyCodeFirstEntityChangedArgs()
{
Id = existingRecord.Id,
ChangeReason = "Updated"
});
}
}
}
これで、次のように、どこからでもイベント ハンドラーをモデルにアタッチできます (静的イベント ハンドラー)。
MyCodeFirstEntity.EntityChanged += new EventHandler<MyCodeFirstEntityChangedArgs>(MyCodeFirstEntity_LocalEventHandler);
次に、このイベントが発生するたびにローカル UI ビューを更新するハンドラーを各ビューに配置します。
static void MyCodeFirstEntity_LocalEventHandler(object sender, MyCodeFirstEntityChangedArgs e)
{
// Something somewhere changed a record! I better refresh some local UI view.
}
これで、すべての UI コンポーネントが重要なイベントをサブスクライブできるようになりました。ツリー リストといくつかのエディタ フォームがある場合、ツリー リストはノードを追加/更新/削除するための変更をサブスクライブします (または簡単な方法 - ツリー リスト全体を更新するだけです)。
アプリケーション間の更新
さらに一歩進んで、接続された環境でアプリの個別のインスタンスをリンクしたい場合は、Microsoft Technology Stack のコメット実装である WebSyncなどを使用して、ネットワーク経由で pub/sub イベント システムを実装できます。WebSync には、サブスクライブまたはパブリッシュするエンティティ/イベントごとに、イベントを論理的な「チャネル」に分割するためのすべての機能が組み込まれています。はい、私は WebSync を作成しているソフトウェア会社で働いています。:-)
ただし、商用の実装にお金を払いたくない場合は、エンティティが変更されたときに上記のイベントの通知を配布する独自の TCP ソケット クライアント/サーバーを作成できます。次に、サブスクライブしているアプリがネットワーク経由で通知を受け取ると、同じ方法でローカル イベント ハンドラーを起動して、ローカル ビューを更新できます。データ コンテキストの設計が不十分な静的インスタンスでは、これを行うことはできません (アプリのインスタンスを 1 つだけ実行する必要があります)。早い段階で適切なセットアップを行えば、ネイティブ アプリと Web アプリの複数のインスタンスで同時に動作する分散型 pub-sub システムを後から簡単に追加できます。それは非常に強力になります。