1

MVC アプリケーション内からバス上でメッセージを送信するのと同じトランザクションで、NHibernate を使用してデータベースに保存しようとしています。

public void DoSomethingToEntity(Guid id)
{
    var session = _sessionFactory.OpenSession();
    CurrentSessionContext.Bind(session);

    using (var transactionScope = new TransactionScope())
    {
        var myEntity = _session.Get(id);
        myEntity.DoSomething();
        _session.Save(myEntity);
        _bus.Send(myMessage);
        transactionScope.Complete();
    }

    session.Dispose();
}

構成では、.MsmqTransport() は .IsTransactional(true) で設定されます。

メッセージ ハンドラー (独自のトランザクションにラップされているため、TransactionScope は必要ありません) 内でこれを行うと、すべてが期待どおりに機能し、例外を含めると、両方とも失敗します。

ただし、MVC アプリケーションで自分のトランザクション内でこれを行うと、using ブロックを離れるときに transactionScope.Complete() の後に次のエラーが発生します。

「この操作は、入隊の現在の状態では無効です。」

スタック トレース: System.Transactions.EnlistmentState.InternalIndoubt(InternalEnlistment enlistment) で System.Transactions.VolatileDemultiplexer.BroadcastInDoubt(VolatileEnlistmentSet& volatiles) で System.Transactions.TransactionStatePromotedIndoubt.EnterState(InternalTransaction tx) で System.Transactions.TransactionStatePromotedBase.InDoubtEnlistment(InternalTransaction tx) ) System.Transactions.DurableEnlistmentDelegated.InDoubt (InternalEnlistment 登録、例外 e) で System.Transactions.SinglePhaseEnlistment.InDoubt (例外 e) で System.Data.SqlClient.SqlDelegatedTransaction.SinglePhaseCommit (SinglePhaseEnlistment 登録) で System.Transactions.TransactionStateDelegatedCommitting.EnterState (InternalTransaction tx) System.Transactions.TransactionStateDelegated で。BeginCommit(InternalTransaction tx, Boolean asyncCommit, AsyncCallback asyncCallback, Object asyncState) System.Transactions.CommittableTransaction.Commit() で System.Transactions.TransactionScope.InternalDispose() で System.Transactions.TransactionScope.Dispose() で HumanResources.Application.Implementations .HolidayService.Book(BookHolidayRequest request) in C:\Users\paul.davies\Documents\GitHub\EdaCalendarExample\HumanResources.Application\Implementations\HolidayService.cs: 76 行目、HumanResources.UI.Controllers.HolidayController.BookUpdate(BookHolidayViewModel viewModel) C:\Users\paul.davies\Documents\GitHub\EdaCalendarExample\HumanResources.UI\Controllers\HolidayController.cs:行 82 の lambda_method(Closure , ControllerBase , Object[] ) at System.Web.Mvc.ActionMethodDispatcher.Execute( ControllerBase コントローラー、System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary) の Object[] パラメーター)2 parameters) at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary2 つのパラメーター) System.Web.Mvc.ControllerActionInvoker.<>c_ DisplayClass15.b _12() at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter フィルター、ActionExecutingContext preContext、Func`1 継続)

最新の編集:

このコードは機能します:

public void DoSomethingToEntity(Guid id)
{
    var session = _sessionFactory.OpenSession();
    CurrentSessionContext.Bind(session);

    using (var transactionScope = new TransactionScope())
    {
        var myEntity = _session.Get(id);
        _bus.Send(myMessage);
        transactionScope.Complete();
    }

    session.Dispose();
}

このコードはエラーを作成します:

public void DoSomethingToEntity(Guid id)
{
    var session = _sessionFactory.OpenSession();
    CurrentSessionContext.Bind(session);

    using (var transactionScope = new TransactionScope())
    {
        var myEntity = _session.Get(id);
        myEntity.AnyField = "a new value";
        _bus.Send(myMessage);
        transactionScope.Complete();
    }

    session.Dispose();
}

どちらの例でもエンティティを保存していないことに注意してください。違いは 2 番目の例にあります。NHibernate から取得したエンティティを変更しています。これは 100% 再現可能です。

4

2 に答える 2

4

これは関連していない可能性がありますが、セッション フラッシュ モードが - に設定されている場合でも、_session.Flush()コミットする前に呼び出す必要があります。これは、NH が提供するトランザクションに対してのみ機能します。TransactionScopeCommit

于 2012-09-21T14:17:04.460 に答える
0

私が知る限り、新しい System.Transactions.Transaction が作成されたときに通知される方法はなく、NHibernate のコードを見ると、TransactionScope が作成された状況に対処するコードがないようです。セッションを作成した後。

セッションを作成すると、現在のトランザクションに参加しようとします。存在しない場合、セッションはトランザクションに参加しません。これがコミット時にトランザクションが失敗する原因であると思われます。

TransactionScope 内でセッションを作成することをお勧めします。また、TransactionScope の前のどこかで session.BeginTransaction を呼び出しているかどうかも確認してください。

于 2012-09-19T16:22:59.417 に答える