3

これが重複した質問のように思われる場合は、事前にお詫び申し上げます。この質問は私が見つけた最も近いものでしたが、私が直面している問題を実際には解決していません。

ASP.NETMVC4アプリケーションでEntityFramework5を使用していて、作業単位パターンを実装しようとしています。

IDisposable私の作業単位クラスは、派生オブジェクトコンテキストクラスの単一インスタンスとDbContext、通常のすべてのリポジトリ機能を公開する汎用ベースリポジトリクラスから派生する多数のリポジトリを実装して含みます。

Ninjectは、HTTPリクエストごとに、Unit of Workクラスの単一のインスタンスを作成してコントローラーに挿入し、リクエストが完了すると自動的に破棄します。

EF5はデータストレージを抽象化し、Ninjectはオブジェクトコンテキストの存続期間を管理するため、永続性を明示的に管理する必要なしに、コードを消費してメモリ内のエンティティオブジェクトにアクセスするための完璧な方法のようです。言い換えると、関心の分離を最適化するために、コントローラーのアクションメソッドが、SaveChanges後で明示的に呼び出す必要なしにリポジトリデータを使用および変更できることを想定しています。

このアイデアを実装するための私の最初の(ナイーブな)試みは、SaveChangesデータを変更するすべてのリポジトリ基本クラスメソッド内への呼び出しを採用しました。もちろん、これはパフォーマンスが最適化されていないこと(特に、同じメソッドを複数回連続して呼び出す場合)でも、アクションメソッドがリポジトリから取得したオブジェクトのプロパティを直接変更する状況にも対応していないことにすぐに気付きました。

そこで、これらの時期尚早な呼び出しを排除しSaveChanges、Unit of Workインスタンスが破棄されたときに、それらを単一の呼び出しに置き換えるように設計を進化させました。作業単位は当然リクエストにスコープされているため、これはMVCでの作業単位パターンの最もクリーンな実装のように見えました。

残念ながら、この概念を構築した後、私はその致命的な欠陥を発見しました。つまり、に追加または削除されたオブジェクトDbContextは、呼び出されるまでローカルでも反映されないSaveChangesという事実です。

では、コードを消費することで、オブジェクトを明示的に永続化せずにオブジェクトを使用できるようにする必要があるという考えについて、あなたはどう思いますか?そして、このアイデアが有効であると思われる場合、EF5でそれを達成するための最良の方法は何ですか?

あなたの提案に感謝します、

ティム

更新:@Wahidの応答に基づいて、消費するコードが明示的に呼び出すことが不可欠になる状況のいくつかを示すいくつかのテストコードを以下に追加しますSaveChanges

var unitOfWork = _kernel.Get<IUnitOfWork>();
var terms = unitOfWork.Terms.Entities;

// Purge the table so as to start with a known state 
foreach (var term in terms)
{
    terms.Remove(term);
}

unitOfWork.SaveChanges();

Assert.AreEqual(0, terms.Count());

// Verify that additions are not even reflected locally until committed.
var created = new Term { Pattern = "Test" };
terms.Add(created);
Assert.AreEqual(0, terms.Count());

// Verify that additions are reflected locally once committed.
unitOfWork.SaveChanges();
Assert.AreEqual(1, terms.Count());

// Verify that property modifications to entities are reflected locally immediately 
created.Pattern = "Test2";
var another = terms.Single(term => term.Id == created.Id);
Assert.AreEqual("Test2", another.Pattern);
Assert.True(ReferenceEquals(created, another));

// Verify that queries against property changes fail until committed
Assert.IsNull(terms.FirstOrDefault(term => term.Pattern == "Test2"));

// Verify that queries against property changes work once committed
unitOfWork.SaveChanges();
Assert.NotNull(terms.FirstOrDefault(term => term.Pattern == "Test2"));

// Verify that deletions are not even reflected locally until committed.
terms.Remove(created);
Assert.AreEqual(1, terms.Count());

// Verify that additions are reflected locally once committed.
unitOfWork.SaveChanges();
Assert.AreEqual(0, terms.Count());
4

1 に答える 1

7

まず第一に、リポジトリにあるSaveChangesべきではありません。それはあなたがの利益を失うことにつながるからですUnitOfWork

次に、の変更を保存するための特別なメソッドを作成する必要がありますUnitOfWork

また、このメソッドを自動的に呼び出したい場合はActionFilter、すべてのコントローラーがBaseControllerクラスから継承し、その中で処理するようにするなど、他のソリューションを微調整することができますSaveChanges

とにかく、UnitOfWork常にSaveChangesメソッドが必要です。

于 2012-12-09T13:07:20.800 に答える