7

次のアーキテクチャで.Netアプリケーションを開発しています:プレゼンテーション層(ASP.Net MVC 2でMVCパターンを使用)、サービス層、データアクセス層(Entity Frameworkでリポジトリパターンを使用)。

トランザクション管理をサービスレイヤーに配置することにしましたが、それを実装する方法がわかりません。トランザクションをサービスレイヤーレベルで完全に制御したいと考えています。つまり、コントローラーがサービスレイヤーのメソッドを呼び出すたびに、データベースの更新に関する不可分操作である必要があります。

サービスレイヤーで提供される異なるサービス間に関係がない場合、それは単純です。各メソッドは、実行の最後に変更をコミットする必要があります(つまり、使用するコンテキストでsaveメソッドを呼び出します)。ただし、サービス層のサービスが連携する場合もあります。

例:次のパラメータを受け取る確認メソッドを備えた出荷サービスを提供します:出荷ID、新規顧客または既存顧客に対応するかどうかを示すフラグ、顧客ID(出荷確認が既存の顧客の場合)顧客)および顧客名(新規顧客の場合)。フラグが「新規顧客」に設定されている場合、サービスレイヤーは(a)顧客を作成し、(b)出荷を確認する必要があります。(a)の場合、出荷サービスはカスタマーサービスを呼び出します(新しいカスタマーを作成してデータベースに保存するために必要な検証とロジックをすでに実装しています)。

このシナリオで誰が変更をコミットする必要がありますか?

  • カスタマーサービスはそれを行うべきですか?新しい顧客の作成後に変更をコミットすることはできません。これは、出荷確認メソッドの後半で問題が発生する可能性があるためですが、直接呼び出された場合(他のユースケースでは、クライアントを作成するために提供されます)に変更をコミットする必要があります。
  • サービスメソッドを呼び出すコントローラーはそれを行う必要がありますか?ただし、コントローラーはトランザクションについて何も知らないはずです。すべてのトランザクションの知識をサービスレイヤーに配置することにしました。
  • サービス層のトランザクションマネージャー?それをどのように設計するのですか?、誰がいつそれを呼ぶのですか?

従うべきこのためのデザインパターンはありますか?

4

2 に答える 2

5

サービスにCommit()があります。これは、UnitOfWorkがサービスによって作成された場合にのみコミットし、コンストラクターに渡された場合、コミットは何もしません。

サービスに2番目の(内部)コンストラクターを使用しました。

public class MyService
{
private IUnitOfWork _uow;
private bool _uowInternal;

public MyService()
{
    _uow = new UnitOfWork();
    _uowInternal = false;
}

internal MyService(IUnitOfWork uow)
{
    _uow = uow;
    _uowInternal = true;
}
public MyServiceCall()
{
    // Create second service, passing in my UnitOfWork:
    var svc2 = new MySecondService(_uow);

    // Do your stuff with both services.
    ....
    // Commit my UnitOfWork, which will include all changes from svc2:
    Commit();
}

public void Commit()
{
    if(!_uowInternal)
        _uow.Commit();
}
}
于 2011-02-03T15:42:05.530 に答える
1

EFの代わりにWCFとL2Sを使用する同様のアーキテクチャでは、メインのサービスインターフェイス実装クラスでトランザクションを使用することを選択しました。これを実現するためにTransactionScopeを使用しました。

public void AServiceMethod() {
    using(TransactionScope ts = new TransactionScope()) {
         service1.DoSomething();
         service2.DoSomething();
         ts.Complete();
    }
}

主な欠点は、トランザクションが大きくなる可能性があることです。その場合、たとえばトランザクションブロック内のサービス呼び出しの1つが読み取り専用アクセスのみを必要とする場合TransactionScope(TransactionScopeOption.Suppress)、トランザクションの存続期間中に行/テーブルがさらにロックされないように、ネストされたブロックでラップします。

于 2011-02-01T19:40:55.970 に答える