2014-02-14 69 views
2

我們爲我們的系統必須爲用戶提供明確的環境發佈數據的變化到另一個儀表板架構的一個組成部分。我們研究了NH Evers,但我們需要許多領域特定的東西來烘焙到架構中。我們已經成功地使用NHibernate的事件模型來跟蹤和記錄在我們的系統狀態變化(另一個表),但最近遇到與組件一個障礙絆倒。當IPostInsertEventListener和IPostUpdateEventListener燒製它發佈的是表示實體的當前狀態的值的陣列。在更新的情況下,它也發佈一個表示前一個狀態的數組。我們正在使用這些數組來將「之前」和「之後」狀態保存到我們的表中。當屬性是組件時,實際值(區域中的項目)是組件實例本身 - 即無類型的複雜對象。短交叉引用的元模型映射和反映上拔出個人價值觀,我怎樣才能在組成成分的實際值?我能夠得到映射到組件成員的列名,但不能獲得前後值。NHibernate的變更審計和組件

我已經挖通過NH來源,我沒有找到如何把這些價值,但顯然NH知道如何做到這一點的內部,因爲它是能夠正確發佈的SQL。下面的代碼我目前有突出問題的修改/詳細的版本:

 public static RowChangedReport Load(IChangeTrackable trackable, object entityId, AbstractEntityPersister persister, object[] state, object[] oldState) 
    { 
     var report = new RowChangedReport 
      { 
       Entity = trackable, 
       EntityTypeFullName = persister.EntityName, 
       TableName = new TableName(persister.GetTableName()), 
       EntityId = entityId, 
      }; 

     var authContext = AuthenticationContext.Current; 

     if (authContext != null) 
      report.SecurityContextUserId = authContext.UserId; 

     if (persister.PropertyNames != null && state != null) 
     { 
      report.ChangedType = oldState == null ? RowChangedTypes.New : RowChangedTypes.Modified; 

      for (var index = 0; index < persister.PropertyNames.Length; index++) 
      { 
       var propertyName = persister.PropertyNames[index]; 

       IType propertyType = persister.PropertyTypes[index]; 

       if (!propertyType.IsCollectionType) 
       { 
        AddColumnChangeReport(persister, state, oldState, index, propertyName, report); 
       } 
      } 
     } 

     report.FinalizeState(); 

     return report; 
    } 

    private static void AddColumnChangeReport(AbstractEntityPersister persister, object[] state, object[] oldState, int index, string propertyName, RowChangedReport report) 
    { 
     var currentValue = state[index]; 

     // for simple properties, this is always a single element array 
     // for components, this is an array with an element for each member on the component - i.e. how the component is mapped 
     string[] columns = persister.GetPropertyColumnNames(propertyName); 

     var previousValue = oldState == null ? null : oldState[index]; 

     if (!Equals(currentValue, previousValue)) 
     { 
      if (report.ChangedType == RowChangedTypes.Modified && propertyName == IsActivePropertyName) 
       report.FlagAsDeleted(); 

      foreach (var column in columns) 
      { 
       // if this is a component, both the currentValue and the previousValue are complex objects 
       // need to have a way to get the actual member value per column! 
       report.AddChange(new ColumnChangedReport(report, propertyName, column, previousValue, currentValue)); 
      } 
     } 
    } 
+0

提供上面的解決方案與解決方案 – kellyb

回答

0

OK,幾個小時後讀NH代碼,我偶然發現定義的tuplizer並跟蹤他們回到物業類型。因此,解決辦法很簡單 - 對於組件,您需要將其作爲檢測等,投射到COMPONENTTYPE類型,然後問COMPONENTTYPE的屬性值。這裏有一些代碼適用於我:

 public static RowChangedReport Load(IChangeTrackable trackable, object entityId, AbstractEntityPersister persister, object[] state, object[] oldState) 
    { 
     var report = new RowChangedReport 
      { 
       Entity = trackable, 
       EntityTypeFullName = persister.EntityName, 
       TableName = new TableName(persister.GetTableName()), 
       EntityId = entityId, 
      }; 

     var authContext = AuthenticationContext.Current; 

     if (authContext != null) 
      report.SecurityContextUserId = authContext.UserId; 

     if (persister.PropertyNames != null && state != null) 
     { 
      report.ChangedType = oldState == null ? RowChangedTypes.New : RowChangedTypes.Modified; 

      for (var index = 0; index < persister.PropertyNames.Length; index++) 
      { 
       var propertyName = persister.PropertyNames[index]; 

       IType propertyType = persister.PropertyTypes[index]; 

       if (!propertyType.IsCollectionType) 
       { 
        AddColumnChangeReport(persister, state, oldState, index, propertyName, propertyType, report); 
       } 
      } 
     } 

     report.FinalizeState(); 

     return report; 
    } 

    private static void AddColumnChangeReport(AbstractEntityPersister persister, object[] state, object[] oldState, int index, string propertyName, IType propertyType, RowChangedReport report) 
    { 
     var currentValue = state[index]; 

     string[] columns = persister.GetPropertyColumnNames(propertyName); 

     var previousValue = oldState == null ? null : oldState[index]; 

     if (!Equals(currentValue, previousValue)) 
     { 
      if (report.ChangedType == RowChangedTypes.Modified && propertyName == IsActivePropertyName) 
       report.FlagAsDeleted(); 

      if (propertyType.IsComponentType) 
      { 
       ComponentType component = (ComponentType)propertyType; 

       object[] componentCurrentValues = null; 

       if (currentValue != null) 
        componentCurrentValues = component.GetPropertyValues(currentValue, EntityMode.Poco); 

       object[] componentPreviousValues = null; 

       if (currentValue != null) 
        componentPreviousValues = component.GetPropertyValues(previousValue, EntityMode.Poco); 

       if ((componentCurrentValues != null && componentCurrentValues.Length != columns.Length) || 
        (componentPreviousValues != null && componentPreviousValues.Length != columns.Length)) 
        throw new ConventionViolationException(GetComponentArraysExceptionMessage(persister, propertyName, columns, componentPreviousValues, componentCurrentValues)); 

       for (int i = 0; i < columns.Length; i++) 
       { 
        var column = columns[i]; 
        var componentPreviousValue = componentPreviousValues == null ? null : componentPreviousValues[i]; 
        var componentCurrnetValue = componentCurrentValues == null ? null : componentCurrentValues[i]; 

        report.AddChange(new ColumnChangedReport(report, propertyName, column, componentPreviousValue, componentCurrnetValue)); 
       } 
      } 
      else 
      { 
       if (columns.Length > 1) 
        throw new ConventionViolationException("Expected only component properties to have multiple columns. Property '{0}' on entity {1} is violating that assumption.".FormatWith(propertyName, persister.EntityName)); 

       report.AddChange(new ColumnChangedReport(report, propertyName, columns[0], previousValue, currentValue)); 
      } 
     } 
    }