2009-07-28 7 views
17

NHibernateでネストされたトランザクションを実行できますか?どのように実装しますか?私はSQL Server 2008を使用しているので、サポートは間違いなくDBMSにあります。時間によって、その後NHibernateでどのようにネストされたトランザクションを行うのですか?

using (var outerTX = UnitOfWork.Current.BeginTransaction()) 
{ 
    using (var nestedTX = UnitOfWork.Current.BeginTransaction()) 
    { 
     ... do stuff 
     nestedTX.Commit(); 
    } 

    outerTX.Commit(); 
} 

それがセッションAdoTransactionに説明ObjectDisposedExceptionにトランザクションが非アクティブになったouterTX.Commit()、結果に来る:

は、私はこのような何かをしようとすることを見つけます。

代わりに入れ子になったNHibernateセッションを作成するはずですか?または、トランザクションをラップするために使用する必要がある他のクラスがあります(TransactionScopeについて聞いたことがありますが、それが何であるか分かりません)。

私は現在Ayende's UnitOfWork implementation(thanks Sneal)を使用しています。

私はこの疑問を否定できない、私はまだNHibernateの新人です。

ありがとうございます!

EDIT:私はあなたのような、のTransactionScopeを使用することができることを発見した:それはSQL Serverを使用するには、私たちをロックして、私は、このことについてすべてのこと興奮していないよしかし

using (var transactionScope = new TransactionScope()) 
{ 
    using (var tx = UnitOfWork.Current.BeginTransaction()) 
    { 
     ... do stuff 
     tx.Commit(); 
    } 

    using (var tx = UnitOfWork.Current.BeginTransaction()) 
    { 
     ... do stuff 
     tx.Commit(); 
    } 

    transactionScope.Commit(); 
} 

、およびまた、データベースがリモートの場合、MSDTCを有効にすることについて心配する必要があることがわかりました。ネストされたトランザクションは、SQLで非常に便利で簡単です。私はNHibernateが同じことをエミュレートする何らかの方法を持っていると想定しています...

+1

あなたは答えを見つけることができたことがありますか?最後にネストされたトランザクションを行う方法は? – learning

+0

@ user281180、sort of私は実際にそれらを行う方法は見つけられませんでしたが、あなたはその経験を近似することができます。それについてブログに投稿してください:http://blog.constructionhive.com/2010/07/22/nested-transactions-and-nhibernate/ – Gavin

答えて

1

ネスティングの使用を希望する場合、その実装はネストをサポートしません。Ayende's UnitOfWork implementationあなたが使っている実装のもう一つの問題は(少なくともWebアプリケーションの場合)、それが静的変数でISessionインスタンスに保持されていることです。

私はUnitOfWorkを昨日書き直したばかりですが、元々はGabriel'sに基づいていました。

UnitOfWork.Current.BeginTransaction()は使用しません。すべての変更を一度にフラッシュするために、最後に個別のトランザクションを作成するUnitofWork.TransactionalFlush()を使用します。

using (var uow = UnitOfWork.Start()) 
{ 
    var entity = repository.Get(1); 
    entity.Name = "Sneal"; 
    uow.TransactionalFlush(); 
} 
+0

ええ、最初からRhino Commonsを使うべきだったような気がします...私は思います私はGabrielと一緒に行ったので、Unit Of Workパターンが最初から構築することによってどのように働いたのかを知ることができました(実際に私の理解を助けてくれました)が、今は大きな男の子と遊ぶ時間です...ありがとう。 – Gavin

+0

@Sneal:私たちはRhino.Commonsを使用してAyendeのUnitOfWorkを実装しました。それは良いことですが、ネストされたトランザクションをどのように動作させるかについてはまだ不明です。元の質問で説明したコードは、以前と全く同じように動作します(つまり、トランザクションオブジェクトは共有されているように見えます)。あなたは私に何か指摘してもらえますか?おかげさまで – Gavin

2

私はしばらくの間これを苦労してきました。それに別の亀裂があるだろうか。

個々のサービスコンテナにトランザクションを実装したいのですが、それはそれらを自己完結型にしていますが、大規模なトランザクション内にこれらのサービスメソッドを入れ子にし、必要に応じて全体をロールバックすることができるからです。

私はRhino Commonsを使用しているため、With.Transactionメソッドを使用してリファクタリングを試行します。基本的には、トランザクションがネストされているかのようにコードを書くことができますが、実際には1つしかありません。例えば

Test_NoNestedTransaction()

private Project CreateProject(string name) 
{ 
    var project = new Project(name); 
    With.Transaction(delegate 
    { 
     UnitOfWork.CurrentSession.Save(project); 
    }); 
    return project; 
} 

private Sample CreateSample(Project project, string code) 
{ 
    var sample = new Sample(project, code); 
    With.Transaction(delegate 
    { 
     UnitOfWork.CurrentSession.Save(sample); 
    }); 
    return sample; 
} 

private void Test_NoNestedTransaction() 
{ 
    var project = CreateProject("Project 1"); 
} 

private void TestNestedTransaction() 
{ 
    using (var tx = UnitOfWork.Current.BeginTransaction()) 
    { 
     try 
     { 
      var project = CreateProject("Project 6"); 
      var sample = CreateSample(project, "SAMPLE006", true); 
     } 
     catch 
     { 
      tx.Rollback(); 
      throw; 
     } 
     tx.Commit(); 
    } 
} 

、我々は、より大きなトランザクションのコンテキストなしで単独でプロジェクトを作成しています。この場合、CreateSampleに新しいトランザクションが作成され、コミットされるか、例外が発生するとロールバックされます。

Test_NestedTransaction()では、サンプルとプロジェクトの両方を作成しています。何かがうまくいかない場合は、両方をロールバックする必要があります。実際には、CreateSampleCreateProjectというコードはまったくトランザクションがないように実行されます。ロールバックするかコミットするかを決定する外部トランザクションであり、例外がスローされたかどうかに基づいています。実際には、私は外部トランザクションのために手動で作成されたトランザクションを使用しています。私たちはコミットするかロールバックするかを制御します。on-exception-rollback-else-commitです。

はあなたのコードをこの種のものの全体の多くを置くことによってRhino.Commonsせずに同じことを達成できますように

if (!UnitOfWork.Current.IsInActiveTransaction) 
{ 
    tx = UnitOfWork.Current.BeginTransaction(); 
} 

_auditRepository.SaveNew(auditEvent); 
if (tx != null) 
{ 
    tx.Commit(); 
} 

...とを。しかし、With.Transactionは、匿名の代理人を作成する必要があることの頑固さにもかかわらず、非常に便利です。

TransactionScope(MSDTCに依存している点を除きます)を使用するこの方法の利点は、いくつのメソッドが呼び出されたかにかかわらず、最後の外部トランザクションコミットでデータベースに対してただ1回フラッシュするだけでよいことです間につまり、コミットされていないデータをデータベースに書き込む必要はありません。常にローカルのNHibernateキャッシュに書き込みます。

要するに、このソリューションでは、複数のトランザクションを使用することはないため、トランザクションを究極的に制御することはできません。とにかく、ネストされたトランザクションは決してすべてのDBMSで普遍的にサポートされるわけではないので、私はそれを受け入れることができると思います。しかし、おそらく、おそらく私はすでにトランザクションに入っているかどうかを気にせずにコードを書くことができます。

13

NHibernateセッションはネストされたトランザクションをサポートしません。

次のテストでは、バージョン2.1.2には常に真である:

var session = sessionFactory.Open(); 
var tx1 = session.BeginTransaction(); 
var tx2 = session.BeginTransaction(); 
Assert.AreEqual(tx1, tx2); 

あなたはネストされたトランザクションをサポートするためにTransactionScopeでそれをラップする必要があります。

は、MSDTCを有効にする必要があります。また、エラーが発生します。

{"Network access for Distributed Transaction Manager (MSDTC) has been disabled. Please enable DTC for network access in the security configuration for MSDTC using the Component Services Administrative tool."}

+0

これは、NHibernateでネストされたトランザクションを作成したとしても、それらが一番​​外側の接続として扱われることを意味します。 –

2

サティシュが示唆したように、ネストされたトランザクションはNHibernateのではサポートされていません。ネストされたトランザクションが必要なシナリオは見当たりませんでしたが、他の作業単位ですでに他のトランザクションがアクティブになっている場合、トランザクションの作成を無視しなければならない問題に直面しました。

下のブログのリンクはNHibernateのための実装例を提供するだけでなく、SQLサーバーのために働く必要があります。 http://rajputyh.blogspot.com/2011/02/nested-transaction-handling-with.html

関連する問題