2012-01-02 38 views
3

我使用ninject MVC 3和NHibernate和我得到这个错误,当我尝试做一个更新,我不明白为什么有关。用同样的标识值不同的对象已经与会话+ 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。

然后显示在页面上。然后我有一个被调用的保存方法,我尝试将虚拟机绑定到卡域,然后尝试更新它,这是当我得到上述错误。

这些是虽然2个不同的呼叫和会话应当丢弃掉。

Bind<ISessionFactory>().ToProvider<NhibernateSessionFactoryProvider>().InSingletonScope(); 
      Bind<ISession>().ToMethod(context => context.Kernel.Get<ISessionFactory>().OpenSession()).InRequestScope(); 

我不确定是否需要调用另一个dispose或什么。

我用工作单位,所以我说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

检查'EditCard(卡--->卡<--- ...'和'以下nhibernateRepo.Update(--->的信用卡<--- );'好像不同的人还有你创建一个新对象'卡卡=新Card'与已经使用的ID,它帮助 – oleksii 2012-01-02 01:58:26

+0

他们是同样的事情,我的名字缩短下来 – chobo2 2012-01-02 02:00:15

回答

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); 

,以获得正确的状态。它会给你的缓存实例可用时没有击中数据库

+0

为什么是不正确我?。?累了。获取并加载nhibernate配置文件,它确实会触发数据库。那么为什么这会比创建一个新对象并填充id更好?我认为这会导致一个数据库调用不是2(因为您仍然将需要调用一个提交来更新修改)那么你会怎样使用Update()呢? – chobo2 2012-01-02 23:43:09

+0

AFAIK更新也应该打到数据库来知道哪些属性已经改变了,如果你创建一个新的卡对象会哟你不会失去除了你设定的其他所有财产? – Firo 2012-01-03 01:55:31

+0

我不确定在这种情况下会发生什么。在我的情况下,尽管每个选项都可以更改,所以我必须将所有内容发布到数据库。我想也许它可能不得不更新,如果我得到的实际对象。我不认为我可以使用.Get或.Load,因为我需要加载多个表,例如你可以看到Country是另一个表,所以不需要加载? – chobo2 2012-01-03 02:06:15

相关问题