Как реализовать столбцы ChangeTime и ChangeUser с помощью NHibernate?

Я пытаюсь использовать NHibernate с существующей базой данных. В модели данных в каждой таблице есть столбцы, которые содержат время и имя пользователя последнего обновления строки. Как мне сделать это с помощью NHibernate?

Я попытался реализовать перехватчик, который устанавливает ChangeTime и ChangeUser в объектах, прежде чем он будет сохранен с использованием метода IInterceptor.OnSave. Это не сработало, потому что установка этих свойств вызывает обновление строки, даже если никакие другие свойства не были изменены.

Это могло бы сработать, если бы был какой-то способ сказать NHibernate об исключении свойств ChangeTime и ChangeUser, тогда он выполняет грязную проверку. Но я не нашел способа сделать это.

Спасибо за любую помощь.

4 ответа

Решение

Вы должны зарегистрировать слушателя для событий pre insert и pre update. Вы можете сделать это через вашу конфигурацию следующим образом:

<hibernate-configuration>
    ...
    <event type="pre-update">
        <listener class="MyListener, MyAssembly"/>
    </event>
    <event type="pre-insert">
        <listener class="MyListener, MyAssembly"/>
    </event>
</hibernate-configuration>

а затем реализовать слушателя - что-то вроде этого (может быть, не совсем точно - списано из моей памяти):

public class MyListener : IPreUpdateEventListener, IPreInsertEventListener
{
    public bool OnPreUpdate(PreUpdateEvent evt)
    {
        if (evt.Entity is IHasLastModified)
            UpdateLastModified(evt.State, evt.Persister.PropertyNames);

        return false;
    }

    public bool OnPreInsert(PreInsertEvent evt)
    {
        if (evt.Entity is IHasLastModified)
            UpdateLastModified(evt.State, evt.Persister.PropertyNames);

        return false;
    }

    void UpdateLastModified(object[] state, string[] names)
    {
        var index = Array.FindIndex(names, n => n == "LastModified");

        state[index] = DateTime.Now;
    }
}

и сделать то же самое с событием перед обновлением.

РЕДАКТИРОВАТЬ: Это заботится о вставке, а также обновления, и, кажется, работает.

Эй, я просто должен был решить это на проекте, над которым я работаю, вот мой ответ

public interface IDateModified
{
    DateTime Created { get; set; }
    DateTime Modified { get; set; }
}

public class CustomDefaultSaveOrUpdateEventListener 
    : DefaultSaveOrUpdateEventListener
{
    protected override object EntityIsPersistent(SaveOrUpdateEvent evt)
    {
        var entity = evt.Entity as IDateModified;
        if (entity != null)
        {
                entity.Modified = DateTime.Now;
        }

        return base.EntityIsPersistent(evt);
    }

    protected override object EntityIsTransient(SaveOrUpdateEvent evt)
    {
        var entity = evt.Entity as IDateModified;
        if (entity != null)
        {
            entity.Created = entity.Modified = DateTime.Now;
        }

        return base.EntityIsTransient(evt);
    }
}

Затем в моей конфигурации (я использую Fluent NHibernate для настройки своих модульных тестов в коде)

configuration.EventListeners.SaveOrUpdateEventListeners 
= new ISaveOrUpdateEventListener[]
{
    new CustomDefaultSaveOrUpdateEventListener() 
};

AWESOMENESSSSSSSS!

Ответ Mookid верен, хотя я хотел бы отметить, что если кто-то использует S#arp Architecture, конфигурация NHib должна быть настроена следующим образом:

<hibernate-configuration>
    <session-factory>
    ...
        <event type="pre-update">
            <listener class="MyListener, MyAssembly"/>
        </event>
        <event type="pre-insert">
            <listener class="MyListener, MyAssembly"/>
        </event>
    </session-factory>
</hibernate-configuration>

Элементы события входят в элемент session-factory.

Вместо использования LIsteners вы также можете использовать Interceptors: Аудит изменений с помощью interceptor

Другие вопросы по тегам