3

MVC 3、Fluent nHibernate、AutoMapper、および Autofac を使用してプロジェクトのセットアップを完了し、汎用リポジトリ、作業単位パターン、および 3 層設計を利用しました。私は今この問題に来ました:

作業単位がありますが、それをコミットする場所/方法がわかりません。開始するのは簡単です。Autofac を使用し、HTTP リクエストごとに注入します。私の作業単位のコンストラクターがトランザクションを開始します。しかし、私が気付いたのは、次のようなビジネス クラスになってしまったことです。

private readonly IUnitOfWork _unitOfWork;
private readonly IUserRepository _userRepository;

public UserHandler(
    IUserRepository userRepository, 
    IUnitOfWork unitOfWork)
{
    _userRepository = userRepository;
    _unitOfWork = unitOfWork;
}

public void CreateUser(User user)
{
    // Fill the date fields
    user.CreationDt = DateTime.Now;
    user.ModifiedDt = DateTime.Now;

    // Add the user 
    _userRepository.Add(user);

    // Commit the changes
    _unitOfWork.Commit();
}

他のトランザクションを行う必要がない限り、これは素晴らしいことです。しかし、.Add を呼び出した後で、同様のメソッドを使用して別のビジネス クラスを呼び出すことにした場合はどうなるでしょうか。次に、2 つのコミットがありますが、既に完了したトランザクションを終了しようとしているため、爆発すると思われます。

UnitOfWork の Dispose にコミットを入れることを考えましたが、例外が発生した場合は悪いニュースです。UnitOfWork をコントローラーに注入するケースもいくつか見てきましたが、コントローラーがビジネス層をバイパスしてデータベース層を直接呼び出すことで、懸念事項の分離が壊れているため、これは間違っているようです。最後に、私は現在、シャープ アーキテクチャで使用されているような属性を使用することを検討していますがこれが適切なアプローチであるかどうかもわかりません (繰り返しますが、コントローラーに直接アクセス/データ層の知識を与えていませんか?) .

どこにコミットすべきかについて、誰かが知恵を共有できますか?

4

2 に答える 2

2

1 つの要求内でデータベース接続を共有する限り、応答がクライアントに送信されたら、トランザクションを開始してコミットできます。これを実現するために、私は特別なアクション フィルターを率いています。

public sealed class CommitOnSuccess : ActionFilterAttribute
{
    public IUnitOfWork UnitOfWork { get; set; }

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        if (filterContext.Exception == null)
            UnitOfWork.Commit();
    }
}

これが、アクションメソッドを単純で軽量にした方法です

[CommitOnSuccess]
[HttpPost]
public ActionResult Create(ApplicationManagementViewModel model)
{

}

Create メソッド内のリポジトリから取得したエンティティに対して変更が実行されます。

于 2012-06-25T19:35:17.333 に答える
0

アプリケーション終了要求で、作業単位をコミットできます。global.asax.cs ファイルに次の関数を追加します。

protected void Application_EndRequest(object sender, EventArgs e)
    {
     //code to commit unit of work
    }

また、Autofac を使用しているため、スコープIUnitOfWorkを設定InstancePerLifetimeScopeしてクラスを実装IDisposableし、Dispose関数内でセッションをコミットすることもできます。例外が発生したときの問題はどうですか。コードを次のようにチェックできます。

 if ( HttpContext.Current != null && HttpContext.Current.Error != null) 
      transaction.Rollback();
 else
      transaction.Commit();
于 2012-06-25T19:18:56.137 に答える