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(), StatusResponseL开发者_StackOverflowookup.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
I just encountered this and Claiton Lovato's answer didn't work. However Iko's did work. Here's a little more robust version of Iko's. Downside is x2 trips to the db - one for the Get and another for the insert/update.
A possible solution to this is to read the object from the database, copy the fields to the object, and save it.
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);
}
精彩评论