Как реализовать столбцы ChangeTime и ChangeUser с помощью NHibernate?
Я пытаюсь использовать NHibernate с существующей базой данных. В модели данных в каждой таблице есть столбцы, содержащие время и имя пользователя последнего обновления, внесенного в строку. Как мне это сделать с помощью NHibernate?
Я попытался реализовать перехватчик, который устанавливает ChangeTime и ChangeUser в сущности, прежде чем он будет сохранен с использованием метода IInterceptor.OnSave. Это не сработало, потому что установка этих свойств вызывает обновление строки, даже если никакие другие свойства не были изменены.
Это могло бы сработать, если бы был какой-то способ сообщить NHibernate об исключении свойств ChangeTime и ChangeUser, а затем он будет проверять грязность. Но я не нашел способа сделать это.
Спасибо за любую помощь.
Ответы
Ответ 1
Вы должны зарегистрировать прослушиватель для событий предварительной вставки и предварительного обновления. Вы можете сделать это через свою конфигурацию следующим образом:
<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;
}
}
и сделать то же самое с событием предварительного обновления.
РЕДАКТИРОВАТЬ: Это касается как вставки, так и обновления, и, похоже, это работает.
Ответ 2
Эй, я просто должен был решить это в проекте, над которым я работаю, вот мой ответ
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!
Ответ 3
Правильно ответил Mookid, хотя я хотел бы указать, что если вы используете архитектуру S # arp, конфигурацию 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.
Ответ 4
Вместо использования LIsteners вы также можете использовать Interceptors:
Аудит изменений с использованием перехватчика