2011-09-30 120 views
1

以下方法使用新会话查询我的数据库。如果查询成功,它将(通过“锁定”)结果附加到用于支持从数据绑定WinForms网格控件延迟加载的“MainSession”。为什么我得到这个nhibernate NonUniqueObjectException?

如果结果是已经在MainSession,我得到的异常:

NHibernate.NonUniqueObjectException:一个不同的对象与已经与该会话相关联的相同的标识符值:1,实体:BI_OverlordDlsAppCore.OfeDlsMeasurement

当我尝试重新附加,使用Lock方法。

即使我在尝试重新附加它之前将MainSession的结果逐出,也会发生这种情况。

我更新结果时使用了相同的方法,它工作正常。

任何人都可以解释为什么发生这种情况?

我应该如何去调试这个问题?

public static OfeMeasurementBase GetExistingMeasurement(OverlordAppType appType, DateTime startDateTime, short runNumber, short revision) 
    { 
     OfeMeasurementBase measurement; 

     var mainSession = GetMainSession(); 

     using (var session = _sessionFactory.OpenSession()) 
     using (var transaction = session.BeginTransaction()) 
     { 
      // Get measurement that matches params 
      measurement = 
       session.CreateCriteria(typeof(OfeMeasurementBase)) 
         .Add(Expression.Eq("AppType", appType)) 
         .Add(Expression.Eq("StartDateTime", startDateTime)) 
         .Add(Expression.Eq("RunNumber", runNumber)) 
         .Add(Expression.Eq("Revision", revision)) 
         .UniqueResult() as OfeMeasurementBase; 

      // Need to evict from main session, to prevent potential 
      // NonUniqueObjectException if it's already in the main session 
      mainSession.Evict(measurement); 

      // Can't be attached to two sessions at once 
      session.Evict(measurement); 

      // Re-attach to main session 
      // Still throws NonUniqueObjectException!!! 
      mainSession.Lock(measurement, LockMode.None); 

      transaction.Commit(); 
     } 

     return measurement; 
    } 
+0

我不知道预期的行为,但'measurement'对象,你正试图从'mainSession'驱逐不是该会话持有的同一个对象,所以我想知道它是否应该以这种方式工作。 – Jay

回答

2

我在Cross Session Operations找到Ayende的帖子后解决了问题。

的解决方案是使用ISession.Merge获得主会话更新分离测量:

public static OfeMeasurementBase GetExistingMeasurement(OverlordAppType appType, DateTime startDateTime, short runNumber, short revision) 
    { 
     OfeMeasurementBase measurement; 

     var mainSession = GetMainSession(); 

     using (var session = _sessionFactory.OpenSession()) 
     using (var transaction = session.BeginTransaction()) 
     { 
      // Get measurement that matches params 
      measurement = 
       session.CreateCriteria(typeof(OfeMeasurementBase)) 
         .Add(Expression.Eq("AppType", appType)) 
         .Add(Expression.Eq("StartDateTime", startDateTime)) 
         .Add(Expression.Eq("RunNumber", runNumber)) 
         .Add(Expression.Eq("Revision", revision)) 
         .UniqueResult() as OfeMeasurementBase; 

      transaction.Commit(); 

      if (measurement == null) return null; 

      // Merge back into main session, in case it has changed since main session was 
      // originally loaded 
      var mergedMeasurement = (OfeMeasurementBase)mainSession.Merge(measurement); 
      return mergedMeasurement; 
     } 
    }