Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

nhibernate : a different object with the same identifier value was already associated with the session: 2, of entity:

I am getting the following error when i tried and save my "Company" entity in my mvc application

a different object with the same identifier value was already associated with the session: 2, of entity:

I am using an IOC container

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

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

My CompanyRepository

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

}

And Session Helper

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);
    }
like image 483
frosty Avatar asked Jun 06 '10 09:06

frosty


4 Answers

I know this is a bit late and you might already found the solution, but maybe others could benefit from it...

This error is raised from nHibernate when you are updating an instance of an Entity that is saved on the Cache. Basically nHibernate stores your objects on the cache once you loaded it, so next calls would get it from the cache. If you update an instance that is present on the cache nHibernate throws this error otherwise it could cause dirty reads and conflicts regarding loading the old copy of the object. To get around this, you need to remove the object from the cache using the Evict method like:

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

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

Hope this helps.

like image 169
Claiton Lovato Avatar answered Nov 17 '22 08:11

Claiton Lovato


I tried @claitonlovatojr's hack, but I couldn't still handle the error.

All I had to do in my case wasy to replace my ISession.Update(obj) call to ISession.Merge(obj).

In your repository, change:

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

Also, for more information see this answer.

like image 43
Joel Avatar answered Nov 17 '22 08:11

Joel


A possible solution to this is to read the object from the database, copy the fields to the object, and save it. NHibernate session doesn't know anything about the incoming object which was instantiated by an MVC Model Binder.

In certain cases the whole object may not be visible or passed to the View/ViewModel. When saving it should first be read from NHibernate, then updated and saved.

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

This requires parsing/mapping the ViewModel/Class properties to the Domain Model/Class, but in many cases you don't necessarily present them all to be updated in the view so you would need to do it anyway (Can't save partially empty objects on top of old objects).

like image 4
lko Avatar answered Nov 17 '22 09:11

lko


for more agrgessive way you can use the Clear() method

like image 1
Ziv.Ti Avatar answered Nov 17 '22 09:11

Ziv.Ti