другой объект с таким же значением идентификатора уже был связан с сеансом + nhibernate - PullRequest
3 голосов
/ 02 января 2012

Я использую 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. У меня есть один веб-запрос, который получает карту и привязывает ее к виртуальной машине.

Затем отображается на странице. Затем у меня вызывается метод сохранения, и я пытаюсь привязать ВМ к домену карты, а затем пытаюсь обновить его, когда я получаю вышеуказанную ошибку.

Это 2 разных вызова, и сессия должна быть отключена.

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

Кто-нибудь понимает, почему он думает, что он в том же сеансе.

1 Ответ

2 голосов
/ 02 января 2012

Даже если вы утилизируете сеанс, было бы неправильно создавать новую карту для обновления состояния. Вместо

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

чтобы получить правильное состояние. Это даст вам кэшированный экземпляр, когда он будет доступен, не нажимая на базу данных

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...