6

私のプロジェクトでは、エンティティ フレームワーク 4.0 を ORM として使用して、SQL Server にデータを保持しています。

私のプロジェクトは、アプリケーションからのリボンで、メイン フォームにグリッド ビューとナビゲーション ツリーがあり、その上にリボン パネルがあります。私のアプリは基本的に、ビジネス ロジックがほとんどない CRUD UI として動作します。

初めて EF を使用するので、このプロジェクトは、オーケストレーション フォーム (メイン フォームまたはアプリケーションからユーザーへのアプリケーションとして表示されるフォーム) で objectContext のインスタンスを作成して保持し、クエリをグリッド ビューにバインドして開発しました。

リボン パネルのボタンのクリック、グリッド ビューの行のクリックなどのさまざまなイベントに対して、別のウィンドウ フォームを開きます。そのウィンドウ フォームで、別のオブジェクト コンテキストを作成し、そのフォーム クラスのメンバー変数に格納します。

私はいくつかのブログと次のような質問を読みました。

  1. objectcontext の有効期間を決定する方法
  2. Entity Framework と ObjectContext n 層アーキテクチャなど。

オブジェクト コンテキストを共有することを提案する作成者もいれば、短命で共有しないことを提案する作成者もいます。

子フォームの 1 つで objectContext に加えた変更が、それを示した親フォームを反映していない状態にあるため、この混乱状態に達しました。更新しようとしましたが、まだ役に立ちません。実験のために、最初に作成した objectContext を最も親のクラスでコンストラクター インジェクションを介して共有し、変更の反映の問題を解決しました。

すべての子フォームを共有 objectContext に変換するのは、私にとって大きな作業です。しかし、それが価値があるなら、私は準備ができています. それを共有することの潜在的な問題が何であるかわかりませんか?

これは Web には使用せず、マルチスレッド シナリオを計画していないため、objectContext の静的インスタンスを選択する場合があります。必要に応じて、シングルトンとして立ち上がることができます。

私の質問:

  1. 私の状況で ObjectContext を共有するかしないか?
  2. 共有しない場合、1 つの objectContext を他の変更で更新するという現在の問題をどのように解決できますか?
  3. 共有する場合 - どちらがより良い方法でしょうか? 静的かシングルトンか何か?

プロジェクトと環境の詳細は次のとおりです。

  • Winフォーム
  • C#
  • VS 2012
  • EF 4.0、データ ファースト アプローチで作成されたモデル。

多くの質問やブログ投稿を検索して読んだ後、これを投稿しています。読めば読むほど混乱します:)誰かに答えを任せている場合は、ご容赦ください。コメントを通じてそのような説明が求められた場合は、質問を更新しようとします。

4

1 に答える 1

6

あなたの質問

私の状況で 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 システムを後から簡単に追加できます。それは非常に強力になります。

于 2013-03-11T19:50:59.267 に答える