nhibernate: другой объект с таким же значением идентификатора уже был связан с сеансом: 2 объекта: - PullRequest
24 голосов
/ 06 июня 2010

Я получаю следующую ошибку, когда пытаюсь сохранить свою сущность "Компания" в моем приложении mvc

другой объект с таким же значением идентификатора уже был связан с сеансом: 2, объекта:

Я использую контейнер IOC

private class EStoreDependencies : NinjectModule
    {
        public override void Load()
        {

            Bind<ICompanyRepository>().To<CompanyRepository>().WithConstructorArgument("session",
                                                                                       NHibernateHelper.OpenSession());
        }
    }

Репозиторий моей компании

public class CompanyRepository : ICompanyRepository
{
    private ISession _session;

    public CompanyRepository(ISession session)
    {
        _session = session;
    }    

    public void Update(Company company)
    {

        using (ITransaction transaction = _session.BeginTransaction())
        {

            _session.Update(company);
            transaction.Commit();
        }
    }

}

И Помощник Сессии

public class NHibernateHelper
{
    private static ISessionFactory _sessionFactory; 
    const string SessionKey = "MySession";


    private static ISessionFactory SessionFactory
    {
        get
        {
            if (_sessionFactory == null)
            {
                var configuration = new Configuration();
                configuration.Configure();
                configuration.AddAssembly(typeof(UserProfile).Assembly);
                configuration.SetProperty(NHibernate.Cfg.Environment.ConnectionStringName,
                                          System.Environment.MachineName);
                _sessionFactory = configuration.BuildSessionFactory();
            }
            return _sessionFactory;
        }
    }

    public static ISession OpenSession()
    {
        var context = HttpContext.Current;
        //.GetCurrentSession()

        if (context != null && context.Items.Contains(SessionKey))
        {
            //Return already open ISession
            return (ISession)context.Items[SessionKey];
        }
        else
        {
            //Create new ISession and store in HttpContext
            var newSession = SessionFactory.OpenSession();
            if (context != null)
                context.Items[SessionKey] = newSession;

            return newSession;
        }
    }
}

My MVC Action

    [HttpPost]
    public ActionResult Edit(EStore.Domain.Model.Company company)
    {

            if (company.Id > 0)
            {

                _companyRepository.Update(company);
                _statusResponses.Add(StatusResponseHelper.Create(Constants
                    .RecordUpdated(), StatusResponseLookup.Success));
            }
            else
            {
                company.CreatedByUserId = currentUserId;
               _companyRepository.Add(company);
            }


        var viewModel = EditViewModel(company.Id, _statusResponses);
        return View("Edit", viewModel);
    }

Ответы [ 5 ]

37 голосов
/ 06 июля 2010

Я знаю, что это немного поздно, и вы, возможно, уже нашли решение, но, возможно, другие могли бы извлечь из этого пользу ...

Эта ошибка возникает из nHibernate при обновлении экземпляра сущности, сохраненной в кэше. По сути, nHibernate сохраняет ваши объекты в кеше, как только вы загрузили его, поэтому следующие вызовы будут получать его из кеша. Если вы обновляете экземпляр, который присутствует в кеше, nHibernate выдает эту ошибку, иначе это может привести к грязному чтению и конфликтам при загрузке старой копии объекта. Чтобы обойти это, вам нужно удалить объект из кэша, используя метод Evict, например:

public ActionResult Edit(EStore.Domain.Model.Company company) 
{ 

        if (company.Id > 0) 
        { 
            **ISession.Evict(company);**
            _companyRepository.Update(company);

Надеюсь, это поможет.

11 голосов
/ 23 августа 2013

Я попытался взломать @ claitonlovatojr, но все еще не мог обработать ошибку.

В моем случае все, что мне нужно было сделать, это заменить мой ISession.Update(obj) звонок на ISession.Merge(obj).

В вашем хранилище измените:

public void Update(Company company)
{
    using (ITransaction transaction = _session.BeginTransaction())
    {
        //_session.Update(company);
        _session.Merge(company); // <-- this
        transaction.Commit();
    }
}

Кроме того, для получения дополнительной информации см. этот ответ .

4 голосов
/ 23 мая 2013

Возможным решением этой проблемы является чтение объекта из базы данных, копирование полей в объект и его сохранение. Сессия NHibernate ничего не знает о входящем объекте, который был создан с помощью привязки модели MVC.

В некоторых случаях весь объект может не отображаться или передаваться в View / ViewModel. При сохранении его сначала нужно прочитать из NHibernate, а затем обновить и сохранить.

Company cOrig = _companyRepository.Get(company.Id);
cOrig.PropertyToUpdate = company.PropertyToUpdate;
... // Copy the properties to be updated.
// Save the freshly retrieved object! 
// Not the new object coming from the View which NHibernate Session knows nothing about.
_companyRepository.Update(cOrig);

Это требует анализа / сопоставления свойств ViewModel / Class с моделью / классом домена, но во многих случаях вы не обязательно представляете их все для обновления в представлении, поэтому вам все равно придется это делать сохранить частично пустые объекты поверх старых объектов).

1 голос
/ 19 мая 2013

для более агрессивного способа вы можете использовать метод Clear ()

0 голосов
/ 05 июля 2018

Я только что столкнулся с этим, и ответ Клейтон Ловато не сработал. Однако Ико сработал. Вот немного более надежная версия Iko's. Недостатком является x2 поездки в БД - один для получения и другой для вставки / обновления.

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

public void Save(Company company)
{

    Company dbCompany = null;
    //update
    if (company.Id != 0)
    {
        dbCompany = _companyRepository.Get(company.Id);
        dbCompany.PropertyToUpdate = company.PropertyToUpdate;
    }
    //insert
    else
    {
        dbDefaultFreightTerm = company;
    }
    // Save either the brand new object as an insert
    // Or update the original dbCompany object with an update
    _companyRepository.SaveOrUpdate(company);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...