2010-06-06 40 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

相關問題