As I was playing around with NHibernate today, I came accross a rather inconvenient problem. :).
Let me first explain what I wanted to achieve:
For every domain object that I save, I want to persist in the database when the entity has been created, when it has been last updated and by whom. Nothing special, just regular audit-information.
To make this all possible, I've created the following classes / interfaces:
I think this is pretty straightforward and doesn't require any further explanation.
Then, I continued with creating an NHibernate interceptor which would set the Created and Updated dates. (I could also used the
ILifecycle interface instead, but this meant that I would have a dependency to the NHibernate assembly in my 'domain classes assembly', and I don't like that. In fact, the
ILifecycle interface has been deprecated for exactly that reason).
This is an extract from my
AuditInterceptor which would perform the task I wanted (at least, I thought so ... ).
(Note that my
AuditInterceptor is NOT in the same assembly where the
AuditableEntity and other domain base class reside in. This would create a dependency from my base classes to NHibernate and again, I hate this :) ).
The AuditInterceptor (snippet):
As you can see, it is very simple: I only had to implement 2 methods of the IInterceptor interface:
OnSave, which is called when an entity is saved for the first time in the database (INSERT)
OnFlushDirty, which is called when an existing entity is dirty and has to be updated
IAuditableinterface, and if so, I just set the necessary properties (
Updated) to the appropriate values (the current DateTime).
Easy enough, simple, understandable and clean... If only this would work...
During testing, I got the following exception:
----> System.Data.SqlTypes.SqlTypeException : SqlDateTime overflow.
Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM.
at NHibernate.Persister.Entity.AbstractEntityPersister.Insert(Object fields,
Boolean notNull, SqlCommandInfo sql, Object obj, ISessionImplementor session)
As it turns out, NHibernate doesn't 'see' the changes you make to the entity parameter that is passed to the Interceptor methods:
You can however, change the values that are in the
state array parameter. Then NHibernate will correctly persist the changes.
But, I do not like to 'hard-code' property names as strings for obvious reasons (if you change a property, the compiler will not detect that you should change your 'hardcoded property name string', etc...).
Anyway, in order to get my interceptor to work, I have no other choice then messing around with the
In order to get rid of the 'weak-typing', I added a little bit more code.
So, now my classes look like this:
This solution is, IMHO, elegant enough to live with, and it works.
However, maybe someone else has a better, more elegant solution for this ? If so, I'd like to hear from you ...