2010-06-06 37 views
20

我收到以下错误,当我试图挽救这个“公司”的实体在我的MVC应用程序NHibernate的:不同的对象具有相同标识符值已与会话相关:2,实体:

用相同的标识符值不同的物体已经与所述会话相关联:2,实体:

我使用一个IOC容器

private class EStoreDependencies : NinjectModule 
    { 
     public override void Load() 
     { 

      Bind<ICompanyRepository>().To<CompanyRepository>().WithConstructorArgument("session", 
                         NHibernateHelper.OpenSession()); 
     } 
    } 

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

}

和会话助手

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

你可以在单元测试中重现问题吗? – 2010-06-07 09:49:45

回答

32

我知道这是有点晚了,你可能已经找到了解决办法,但也许其他人可以从中受益...

This当您更新保存在缓存中的实体的实例时,nHibernate会引发错误。基本上,nHibernate在你加载它时将你的对象存储在缓存中,所以下一次调用会从缓存中获取它。如果更新缓存中存在的实例,nHibernate会抛出此错误,否则可能会导致脏读取和加载对象旧副本时的冲突。 要解决这个问题,就需要使用集中退出方法就像从缓存中删除对象:

public ActionResult Edit(EStore.Domain.Model.Company company) 
{ 

     if (company.Id > 0) 
     { 
      **ISession.Evict(company);** 
      _companyRepository.Update(company); 

希望这有助于。

+2

嗨,谢谢你回答这个问题,其实这是一个非常糟糕的问题。原来,我的一个实体没有使用与上述解释相关的同一个会话。 – frosty 2010-07-06 11:45:31

+9

这是一个黑客。我敢打赌,问题在于你没有正确刷新并关闭前一个会话。 – 2011-07-27 12:12:10

+1

问题似乎是,NHibernate不能识别新创建的对象(NHibernate Session之外)。看到我的答案。 – lko 2013-05-23 11:07:08

1

更多agrgessive方式,您可以使用Clear()方法

+4

这将清除所有待处理的事务更改。 – gwin003 2013-09-20 18:08:08

3

一个可能的解决方案是,以从数据库中读取对象,字段复制到目标,并将其保存。 NHibernate会话不知道MVC模型绑定器实例化的传入对象。

在某些情况下,整个对象可能不可见或传递给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); 

这需要解析/映射视图模型/类属性的域模型/类,但在很多情况下,你不必出示他们都在视图中更新,所以你需要做反正它(不能在旧对象顶部保存部分空的对象)。

8

我试过@ 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

相关问题