2009-08-26 15 views
1

すべてのレコードに対してユーザの更新が行われるたびにデータベースにログインし、変更されたレコードの古い値と新しい値を保存する必要があります。Nhibernateで更新前のエンティティを比較する(監査の実装)

public override bool OnFlushDirty(
      object entity, 
      object id, 
      object[] currentState, 
      object[] previousState, 
      string[] propertyNames, 
      IType[] types) 

と私は、エンティティの前の状態と現在の状態を比較する必要があると私はこれを行う方法がわからない(それがどの私の一般的な解決策になる必要があります。この監査はので、私はメソッドを持ってNHibernateのにインターセプターとして実装されています

答えて

0

これはまさにあなたが尋ねていることではないと思いますが、答えは単にcurrentState配列をループし、同じインデックス値のpreviousState配列と比較するようです。変更されるプロパティ名は同じインデックスのpropertyName値です

セッション外のエンティティを変更した場合(Nhibernateはこれを「デタッチ」モデルと呼びます)、前の状態にデータが入力されるとは思わないことに注意してください(または、データの高価な再読み取りが原因です)。

私は、監査ログ用にデータベーステーブルでトリガーを使用することをお勧めします。あなたがNHibを通して更新しないときには、この方法でIMHOを行う方がはるかに簡単です。

乾杯!

3

私は同様の質問をしばらく前に聞いた。 Audit Logging Strategiesはまた別の方法のためにこの質問を見て 私はクラスとエンティティタイプが含まれて一般的な監査ログのPOCOクラス、エンティティID、プロパティ名、現在の状態、以前のようIInterceptorを実装することになった何how-do-i-implement-changetime-and-changeuser-columns-using-nhibernate

状態、変更のタイプ(挿入、更新、削除)、および変更が発生した日時。

次に、私が監査したい各クラスを識別できるように空のインターフェイスIAuditableを作成しました。

OnFlushDirty、OnDelete、および私が今考えることのできない別のイベントでは、変更されたプロパティごとに新しい監査ログクラスが追加されました。

私が家に帰って、私が現在使っているコードにアクセスすると、この質問が更新されます。

また編集 Frederik Gheysels' DevLog - NHibernate IInterceptor: an AuditInterceptor

を見て - 私はそれはたくさん臭いんとしてそれをリファクタリングする必要がありますが、一度に、私はちょうど仕事に何かを必要とし、この再びそれを見てみると実装
との答えを更新私が思いついたものです。

これは私がクラス

<class name="AuditLog" table="AuditLog" lazy="true" > 
     <id name="_persistenceId" column="Id" type="Guid" access="field" unsaved-value="00000000-0000-0000-0000-000000000000" > 
      <generator class="guid.comb" /> 
     </id> 
     <version name="_persistenceVersion" column="RowVersion" access="field" type="int" unsaved-value="0"/> 
     <property name="CreatedDate" column="CreatedDate" type="DateTime" /> 
     <property name="UpdatedBy" column="UpdatedBy" type="string" length="100" /> 
     <property name="EntityID" column="EntityID" type="guid" not-null="true" /> 
     <property name="EntityName" column="EntityName" type="String" length="100" not-null="true" /> 
     <property name="PropertyName" column="PropertyName" type="String" length="100" not-null="true" /> 
     <property name="ActionType" column="ActionType" type="Char" length="1" not-null="true" /> 
     <property name="OldValue" column="OldValue" type="String" length="1000" not-null="false" /> 
     <property name="NewValue" column="NewValue" type="String" length="1000" not-null="false" /> 
    </class> 

を使用しているNHibernateのマッピングでは、これらの特性の各々を実装する一般的なPOCOクラスです。

IInterceptorの実装は(VB.Netでは)次のようになり

Imports Rhino.Commons 
Public Class AuditInterceptor 
Inherits NHibernate.EmptyInterceptor 
Private _auditLogRepository As IAuditLogRepository 
Public Sub New(ByVal [AuditLogRepository] As IAuditLogRepository) 
    _auditLogRepository = [AuditLogRepository] 
End Sub 
Public Overrides Function OnFlushDirty(ByVal entity As Object, ByVal id As Object, ByVal currentState() As Object, ByVal previousState() As Object, ByVal propertyNames() As String, ByVal types() As NHibernate.Type.IType) As Boolean 
'Called on an Update 

    If TypeOf entity Is IAuditable Then 
     Using uow = UnitOfWork.Start(UnitOfWorkNestingOptions.CreateNewOrNestUnitOfWork) 
      If TypeOf entity Is [yourObject] Then 
       aLog = New AuditLog(Now, My.User.Name) 
       With aLog 
        .EntityID = id 
        .EntityName = "[yourObject]" 
        .PropertyName = "[yourProperty]" 
        .ActionType = "U" 
        .OldValue = GetPropertyValue("[yourProperty]", previousState, propertyNames) 
        .NewValue = GetPropertyValue("[yourProperty]", currentState, propertyNames) 
       End With 
       _auditLogRepository.Save(aLog)  
      End if 
      uow.Flush() 
     End Using 
    End If 

    Return MyBase.OnFlushDirty(entity, id, state, propertyNames, types) 
End Function 
Public Overrides Function OnSave(ByVal entity As Object, ByVal id As Object, ByVal state() As Object, ByVal propertyNames() As String, ByVal types() As NHibernate.Type.IType) As Boolean 
'Called on an Insert 

    If TypeOf entity Is IAuditable Then 
     'create a new audit log class here 
    end if 
    Return MyBase.OnSave(entity, id, state, propertyNames, types) 
End Function 
+0

は、メインのエンティティとして同じトランザクションで監査ログを保存していますか? – dariol

+0

私には同じトランザクションの一部である必要があります。そのため、UnitOfWork.Start(UnitOfWorkNestingOptions。CreateNewOrNestUnitOfWork)を使用して、現在のUOWに参加します。私はこの分野で問題を抱えていたことが分かりました。 UOWの一部としてCreateNewOrNestUnitOfWorkオプションを使用すると、その違いが生じました。 –

関連する問題