我正在尝试使用NHibernate在与MVC应用程序内部在总线上发送消息相同的事务中保存到数据库:
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.InDoubtFromEnlistment(InternalTransaction tx)
在System.Transactions.DurableEnlistmentDelegated.InDoubt(InternalEnlistment enlistment,Exception e)
在System.Transactions.SinglePhaseEnlistment.InDoubt(例外e)
在System.Data.SqlClient.SqlDelegatedTransaction.SinglePhaseCommit(SinglePhaseEnlistment enlistment)
在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请求)中的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 [])
在System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase控制器,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()
在System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter过滤器,ActionExecutingContext preContext,Func`1 continuation)
最新修改:
此代码有效:
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 :(得分:4)
这可能没有关系,但即使会话刷新模式设置为_session.Flush()
,您仍需要在提交TransactionScope
之前调用Commit
- 这仅适用于NH提供的事务。
答案 1 :(得分:0)
据我所知,当创建一个新的System.Transactions.Transaction时,没有办法得到通知,并且查看NHibernate中的代码它似乎没有任何代码来处理TransactionScope是在创建会话后创建的。
当您创建会话时,它将尝试在当前事务中登记,如果没有,则会话将不会在事务中登记。我怀疑这是导致事务在提交时失败的原因。
我建议在TransactionScope中创建会话 - 同时检查你是否在TransactionScope之前的某个地方调用session.BeginTransaction。