当我尝试将我的“公司”实体保存在我的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();
}
}
}
和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;
}
}
}
我的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);
}
答案 0 :(得分:37)
我知道这有点晚了你可能已经找到了解决方案,但也许其他人可以从中受益......
当您更新保存在高速缓存上的实体实例时,会从nHibernate引发此错误。基本上,nHibernate在加载后将对象存储在缓存中,因此下一次调用将从缓存中获取它。如果更新缓存中存在的实例,则nHibernate会抛出此错误,否则可能导致脏读取和有关加载对象的旧副本的冲突。 要解决此问题,您需要使用Evict方法从缓存中删除对象,如:
public ActionResult Edit(EStore.Domain.Model.Company company)
{
if (company.Id > 0)
{
**ISession.Evict(company);**
_companyRepository.Update(company);
希望这有帮助。
答案 1 :(得分:11)
我试过@ 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();
}
}
此外,有关详细信息,请参阅this answer。
答案 2 :(得分:4)
可能的解决方案是从数据库中读取对象,将字段复制到对象,然后保存。 NHibernate会话对MVC Model Binder实例化的传入对象一无所知。
在某些情况下,整个对象可能不可见或传递给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属性解析/映射到域模型/类,但在许多情况下,您不一定要在视图中将它们全部更新,因此您无论如何都需要这样做(不能在旧对象上保存部分空对象。)
答案 3 :(得分:1)
对于更积极的方式,您可以使用Clear()方法
答案 4 :(得分:0)
我刚刚遇到了这个问题,克莱顿·洛瓦托(Claiton Lovato)的回答没有用。然而,Iko的确做到了。这是Iko的更强大的版本。缺点是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);
}