Asp.net mvc nhibernate:具有相同标识符值的不同对象已与实体的会话2关联:

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

当我尝试在mvc应用程序中保存我的“公司”实体时,出现以下错误

具有相同标识符值的不同对象已与实体的会话2关联。

我正在使用IOC容器

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