Audit trails using NHibernate's event model often use the OnPreInsert and OnPreUpdate event listeners to change/ modify the state of the entity. Although It may work in some cases and is sometimes referred to as a solution, it should be noted the OnPreInsert and OnPreUpdate events are not intended to be used to change the values of the entity and instead they should be used to check values and for that reason they return "veto"
There is also a bug report about that.
There is a reason for that. NHibernate does the following:
The last point is the critical one. If your PreUpdate trigger changes properties that are not found dirty before and which are not in the same table as the dirty properties, it won't be updated in the database. The same happens when dynamic-update is used.
Example:
<class name="Foo">
<id ...>
<property name="Name"/>
<join table="AnotherTable>
<key name="id"/>
<property name="Value"/>
</join>
</class>
Now, when you change Name in the session (it gets dirty) and Value in the trigger, the table AnotherTable won't be updated.
The correct way is to use the FlushEntityEventListener to implement property changes.The important difference is that you can provide a list of changed properties in this event listener, and therefore tell NHibernate what to store.
There is an example by Buthrakaur.
There is a solution to reproduce the code by Scott Findlaterhere. The tests folder in each project highlights successes/ issues (by failing tests) in each project.
Project - 01OnPreEvents. This project shows a typical, working, approach to audit trails using the OnPreInsert and OnPreUpdate to modify the entity state. An Entity base class which is inherited by a Category class. The base Entity provides identification and common auditing properties.
Project - 02OnPreEventsFailing. This project shows how an inheritance entity hierarchy using the OnPreInsert and OnPreUpdate events to modify entity state fail to persist the changed entity state. Here, for whatever design decision, the Entity base class which originally provide identification and common auditing has been split into Entity and AuditableEntity. Now the Category class inherits from AuditableEntity.
Project - 03Save. Uses the same entity inheritance hierarchy from the 02OnPreEventsFailing project to demonstrate a working version using the Save/ Insert events.
Audit trails using NHibernate's event model are well documented;
There is also this NHibernate bug report - changes made in IPreInsert/UpdateEventListener are not persisted into DB on inherited classes with the resolution of "not an issue" because "pre-insert and pre-update listeners are not intended to be used to change the values of the entity. Instead they should be used to check-values (for that reason they return "veto")." (see in context)
This contradiction of intended usage regarding the changing of entity state was further discussed on this NHUser Group thread, with the same answer.
There are some discussions and blog posts related to this problem: