Как реализовать столбцы 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