Asp.net mvc nhibernate:具有相同标识符值的不同对象已与实体的会话2关联:
当我尝试在mvc应用程序中保存我的“公司”实体时,出现以下错误 具有相同标识符值的不同对象已与实体的会话2关联。 我正在使用IOC容器Asp.net mvc nhibernate:具有相同标识符值的不同对象已与实体的会话2关联:,asp.net-mvc,nhibernate,Asp.net Mvc,Nhibernate,当我尝试在mvc应用程序中保存我的“公司”实体时,出现以下错误 具有相同标识符值的不同对象已与实体的会话2关联。 我正在使用IOC容器 private class EStoreDependencies : NinjectModule { public override void Load() { Bind<ICompanyRepository>().To<CompanyRepository>().WithC
private class EStoreDependencies : NinjectModule
{
public override void Load()
{
Bind<ICompanyRepository>().To<CompanyRepository>().WithConstructorArgument("session",
NHibernateHelper.OpenSession());
}
}
}
和会话助手
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;
}
}
}
我的MVC行动
[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);
}
我知道这有点晚了,你可能已经找到了解决方案,但也许其他人可以从中受益 更新保存在缓存中的实体实例时,会从nHibernate引发此错误。基本上,加载对象后,nHibernate会将对象存储在缓存中,因此下一次调用将从缓存中获取对象。如果更新缓存中存在的实例,nHibernate会抛出此错误,否则可能会导致脏读和加载对象的旧副本时的冲突。 要解决此问题,您需要使用以下逐出方法从缓存中删除对象:
public ActionResult Edit(EStore.Domain.Model.Company company)
{
if (company.Id > 0)
{
**ISession.Evict(company);**
_companyRepository.Update(company);
希望这能有所帮助。要获得更多的帮助,您可以使用Clear()方法。一个可能的解决方案是从数据库读取对象,将字段复制到对象,然后保存它。NHibernate会话对MVC模型绑定器实例化的传入对象一无所知 在某些情况下,整个对象可能不可见或无法传递给视图/视图模型。保存时,应首先从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属性解析/映射到域模型/类,但在许多情况下,您不一定要在视图中显示所有属性以进行更新,因此无论如何都需要这样做(无法在旧对象上保存部分空对象)。我尝试了@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();
}
}
公共作废更新(公司)
{
使用(ITransaction事务=_session.BeginTransaction())
{
//_更新(公司);
_session.Merge(company);//我刚刚遇到了这个问题,Claiton Lovato的答案不起作用。但是Iko的答案起作用了。这里有一个更健壮的Iko版本。缺点是到db的两次访问-一次用于获取,另一次用于插入/更新
一个可能的解决方案是从数据库读取对象,将字段复制到对象,然后保存它
你能在单元测试中重现这个问题吗?嗨,谢谢你回答这个问题,实际上你的问题起草得很糟糕。事实证明,我的一个实体没有使用与你上述解释相关的同一个会话。这是一个黑客行为。我打赌问题在于你没有正确刷新和关闭上一个会话。问题似乎不是hat NHibernate无法识别新创建的对象(在NHibernate会话之外)。请参阅我的答案。因此,与ORM的斗争开始了。
public void Update(Company company)
{
using (ITransaction transaction = _session.BeginTransaction())
{
//_session.Update(company);
_session.Merge(company); // <-- this
transaction.Commit();
}
}
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);
}