我正在使用ninject mvc 3和nhibernate,当我尝试进行更新时出现此错误,我不明白为什么。
NHibernate.NonUniqueObjectException was unhandled by user code
Message=a different object with the same identifier value was already associated with the session: e1a7bd1f-fe1d-4c2e-a459-9fcb0106ad1d, of entity: Card
Source=NHibernate
EntityName=Card
StackTrace:
at NHibernate.Engine.StatefulPersistenceContext.CheckUniqueness(EntityKey key, Object obj)
at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.PerformUpdate(SaveOrUpdateEvent event, Object entity, IEntityPersister persister)
at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.EntityIsDetached(SaveOrUpdateEvent event)
at NHibernate.Event.Default.DefaultUpdateEventListener.PerformSaveOrUpdate(SaveOrUpdateEvent event)
at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.OnSaveOrUpdate(SaveOrUpdateEvent event)
at NHibernate.Impl.SessionImpl.FireUpdate(SaveOrUpdateEvent event)
at NHibernate.Impl.SessionImpl.Update(Object obj)
at CCRecomendator.Framework.Data.Repository.NhibernateRepo.Update[T](T entity) in NhibernateRepo.cs:line 33
at CardService.EditCard(Card card, IList`1 rewardTiersToUseAfterCap) in CardService.cs:line 108
at
CardController.EditCbCreditCard(CbCreditCardFrmVm vm) in CardController.cs:line 505
at lambda_method(Closure , ControllerBase , Object[] )
at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters)
at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass15.<InvokeActionMethodWithFilters>b__12()
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation)
InnerException:
我无法弄清楚为什么它仍然会在nhibernate会话中。我有一个Web请求获取卡并将其绑定到VM。
然后显示在页面上。然后我有一个被调用的save方法,我尝试将VM绑定到Card Domain,然后尝试更新它,这是我收到上述错误时。
这些是两个不同的电话,会话应该被处理掉。
Bind<ISessionFactory>().ToProvider<NhibernateSessionFactoryProvider>().InSingletonScope();
Bind<ISession>().ToMethod(context => context.Kernel.Get<ISessionFactory>().OpenSession()).InRequestScope();
我不确定是否需要再打电话或者说什么。
我使用的是工作单元,所以我添加了一个dispose方法,但不确定何时应该调用它,如果这样可以解决我的问题
public class UnitOfWork : IUnitOfWork, IDisposable
{
private ITransaction transaction;
private readonly ISession session;
public UnitOfWork(ISession session)
{
this.session = session;
session.FlushMode = FlushMode.Auto;
}
/// <summary>
/// Starts a transaction with the database. Uses IsolationLevel.ReadCommitted
/// </summary>
public void BeginTransaction()
{
transaction = session.BeginTransaction(IsolationLevel.ReadCommitted);
}
/// <summary>
/// starts a transaction with the database.
/// </summary>
/// <param name="level">IsolationLevel the transaction should run in.</param>
public void BeginTransaction(IsolationLevel level)
{
transaction = session.BeginTransaction(level);
}
private bool IsTransactionActive()
{
return transaction.IsActive;
}
/// <summary>
/// Commits the transaction and writes to the database.
/// </summary>
public void Commit()
{
// make sure a transaction was started before we try to commit.
if (!IsTransactionActive())
{
throw new InvalidOperationException("Oops! We don't have an active transaction. Did a rollback occur before this commit was triggered: "
+ transaction.WasRolledBack + " did a commit happen before this commit: " + transaction.WasCommitted);
}
transaction.Commit();
}
/// <summary>
/// Rollback any writes to the databases.
/// </summary>
public void Rollback()
{
if (IsTransactionActive())
{
transaction.Rollback();
}
}
public void Dispose() // don't know where to call this to see if it will solve my problem
{
if (session.IsOpen)
{
session.Close();
}
}
[HttpPost]
public ActionResult EditCbCard(CbCardFrmVm vm)
{
if (ModelState.IsValid)
{
Card card = new Card
{
Id = vm.Id, // id of the record in the database
Country = countryService.LoadCountryById(vm.SelectedCountry)
};
CardService.EditCard(card, rewardTiersToUseAfterCap);
}
ModelStateValidationWrapper wrapper = ConvertTo.ModelStateValidationWrapper(creditCardService.ValidationDictionary, ModelState);
return Json(wrapper);
}
public void EditCard(Card card, IList<string> rewardTiersToUseAfterCap)
{
try
{
unitOfWork.BeginTransaction();
nhibernateRepo.Update(creditCard);
unitOfWork.Commit();
}
catch (ADOException ex)
{
ErrorSignal.FromCurrentContext().Raise(ex);
ValidationDictionary.AddError("DbError", ExceptionMsgs.DbError);
unitOfWork.Rollback();
}
catch (SqlException ex)
{
ErrorSignal.FromCurrentContext().Raise(ex);
ValidationDictionary.AddError("DbError", ExceptionMsgs.DbError);
unitOfWork.Rollback();
}
}
任何人都明白为什么它会认为它在同一个会话中。
答案 0 :(得分:2)
即使您处置会话,创建新卡以更新状态也是不正确的。而不是
Card card = new Card
{
Id = vm.Id, // id of the record in the database
Country = countryService.LoadCountryById(vm.SelectedCountry)
};
使用
Card card = unitOfWork.Get<Card>(vm.Id)
card.Country = countryService.LoadCountryById(vm.SelectedCountry);
获得正确的状态。它会在没有命中数据库的情况下为您提供缓存的实例