сравнить сущности перед обновлением в Nhibernate (реализация аудита) - PullRequest
1 голос
/ 26 августа 2009

Мне нужно входить в базу данных при каждом обновлении пользователя любой записи, и мне нужно хранить старое и новое значение любой записи, которая была изменена. Этот аудит реализован как перехватчик в nhibernate, поэтому у меня есть метод:

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

и мне нужно сравнить текущее состояние с предыдущим состоянием объекта, и я не знаю, как это сделать (это должно быть универсальное решение, которое я мог бы применить ко многим типам)

Ответы [ 2 ]

3 голосов
/ 27 августа 2009

Я задал похожий вопрос некоторое время назад. Audit Logging Strategies также посмотрите на этот вопрос по-другому как-делать-я орудие-changetime-и-changeuser-колонки-используя-NHibernate

В итоге я реализовал IInterceptor как класс и универсальный poco-класс Auditlog, который содержал тип сущности, идентификатор сущности, имя свойства, текущее состояние, предыдущее состояние, тип изменения (Вставка, Обновление, Удаление) и дата и время, когда произошло изменение.

Затем я создал пустой интерфейс IAuditable, чтобы можно было идентифицировать каждый класс, который я хотел проверить.

В OnFlushDirty, OnDelete и другом событии, о котором я сейчас не могу думать, добавлены новые классы аудита для каждого измененного свойства.

Я обновлю этот вопрос, когда вернусь домой и у меня будет доступ к коду, который я сейчас использую.

Также смотри DevLog Фредерика Гейселя - NHibernate II Интерцептор: AuditInterceptor

Редактировать - Обновление ответа с реализацией
Глядя на это снова, мне нужно провести рефакторинг, так как он пахнет много, но в то время мне просто нужно было что-то работать, и это то, что я придумал.

Это отображение nhibernate, которое я использовал

    <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>

Этот класс является общим классом poco, который реализует каждое из этих свойств.

Реализация II-рецептора выглядит так (в 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 голосов
/ 27 августа 2009

Я не уверен, что это именно то, что вы спрашиваете, потому что кажется, что ответ - просто перебрать массив currentState и сравнить с массивом previousState для того же значения индекса. Изменяемое имя свойства является значением propertyName с тем же индексом

Я бы предупредил вас, что если вы изменяете свои сущности вне сеанса (Nhibernate называет это «отстраненной» моделью), я не думаю, что предыдущее состояние заполняется (или это вызывает дорогостоящее перечитывание данных для выполнения). это).

Я рекомендую использовать триггеры в таблицах вашей базы данных для ведения журнала аудита. ИМХО гораздо проще сделать это таким образом, и даже работает, когда вы не обновляете через NHib

Ура!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...