2012-09-19 23 views
1

我试图使用NHibernate的在同一事务保存到数据库从一个MVC应用程序内的总线上发送消息NServiceBus消息:发送内部的TransactionScope

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应用程序做我自己的事务中,我得到以下错误transactionScope.Complete()后离开using块:

“的操作是无效的电流时,入伍的状态“。

堆栈跟踪: 在System.Transactions.EnlistmentState.InternalIndoubt(InternalEnlistment征募) 在System.Transactions.VolatileDemultiplexer.BroadcastInDoubt(VolatileEnlistmentSet &挥发物) 在System.Transactions.TransactionStatePromotedIndoubt.EnterState(InternalTransaction TX) 在系统.Transactions.TransactionStatePromotedBase.InDoubtFromEnlistment(InternalTransaction TX) 在System.Transactions.DurableEnlistmentDelegated.InDoubt(InternalEnlistment征募,例外五) 在System.Transactions.SinglePhaseEnlistment.InDoubt(例外五) 在System.Data.SqlClient.SqlDelegatedTransaction.SinglePhaseCommit (唱lePhaseEnlistment征募) 在System.Transactions.TransactionStateDelegatedCommitting.EnterState(InternalTransaction TX) 在System.Transactions.TransactionStateDelegated.BeginCommit(InternalTransaction TX,布尔asyncCommit,的AsyncCallback的AsyncCallback,对象asyncState) 在System.Transactions.CommittableTransaction.Commit() 在System.Transactions.TransactionScope.InternalDispose() 在System.Transactions.TransactionScope.Dispose() 在HumanResources.Application.Implementations.HolidayService.Book(BookHolidayRequest请求)在C:\用户\ paul.davies \文件\ GitHub的\ EdaCalendarExample \ HumanResources.Application \ Implementations \ HolidayService.cs:line 76 at HumanResources.UI.Controllers.HolidayController.BookUpdate(BookHolidayViewModel viewModel)in C:\ Users \ paul.d avies \ Documents \ GitHub \ EdaCalendarExample \ HumanResources.UI \ Controllers \ HolidayController.cs:line 82 at lambda_method(Closure,ControllerBase,Object []) at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller,Object []参数) 在System.Web.Mvc.ReflectedActionDescriptor.Execute(controllerContext controllerContext,IDictionary的2 parameters) at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary 2个参数) 在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(); 
} 

请注意,我没有在任何一个示例中保存实体。不同的是在第二个例子中,我正在修改我从NHibernate获得的实体。这是100%可重现的。

+0

是否可以首先从Web应用程序发送消息,然后让NSB执行数据库更新以及其他后续的Sends()? –

+0

@AdamFyles这将是可能的,并会工作,但会招致性能开销,我敢肯定可以避免。我知道使用TransactionScope是可能的,但我无法越过这个错误。 –

+0

对于谁低估:对我或其他堆栈溢出用户downvote没有解释为什么没有帮助。 –

回答

4

这可能没有关系,但即使会话刷新模式设置为Commit,在提交TransactionScope之前,仍然必须致电_session.Flush() - 只适用于NH提供的事务。

+0

是的,调用session.Flush();在transactionScope.Complete()之前解决了问题。我并不完全明白为什么,而是在事务内部同时拥有NServiceBus和NHibernate(或者更具体地说,ADO.NET,我认为)。 –

0

至于我可以告诉是没有的创建一个新的System.Transactions.Transaction时被通知的方式,并期待在NHibernate的代码它似乎没有任何代码来处理情况TransactionScope是在创建会话之后创建的。

创建会话时,它将尝试登记当前事务,如果没有,那么会话将不会登记到事务中。我怀疑这是导致事务在提交时失败的原因。

我建议在TransactionScope的内部创建会话 - 同时检查是否在TransactionScope之前的某处调用session.BeginTransaction。

+0

这不是NHibernate的问题,它是NServiceBus。据我所知,在创建会话后创建TransactionScope没有任何问题 - 它看起来似乎按我预期的方式工作。无论如何,我尝试过,但结果相同。 –

+0

你确定你发送的队列是事务性的吗?它是一个本地队列还是远程队列? –

+0

队列是事务性的,是的。 –