I am using ninject mvc 3 and nhibernate and I get this error when I try to do an update and I don’t understand why.
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:
I can’t figure out why it would be still be in the nhibernate session. I have one web request that gets the card and binds it to VM.
It then displays on the page. I then have a save method that gets called and I try to bind VM to a Card Domain then try to update it this is when I get the above error.
These are 2 different calls though and the session should be disposed off.
Bind<ISessionFactory>().ToProvider<NhibernateSessionFactoryProvider>().InSingletonScope();
Bind<ISession>().ToMethod(context => context.Kernel.Get<ISessionFactory>().OpenSession()).InRequestScope();
I am not sure if I need to call another dispose or what.
I use the unit of work so I added a dispose method but not sure when I should call it and if this will even solve my problem
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();
}
}
Anyone see why it would think it is in the same session.
Even if you dispose the session it would be incorrect to create a new card to update state. Instead of
use
to get the correct state. It will give you the cached instance when available without hitting the Database