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);
}
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.
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.
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).
for more agrgessive way you can use the Clear() method
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With