Click here to Skip to main content
Click here to Skip to main content

Tagged as

A Flush In The Night

, 11 Jan 2011
Rate this:
Please Sign up or sign in to vote.
Often you want to do some "fix" on your data before pushing it to the database....

Often you want to do some "fix" on your data before pushing it to the database. Typically it's some auditty thingie -- CreatedBy and UpdatedOn kind of stuff. After spreading it all around your application, you finally decide you should keep these things in one place.

If you, like me, is an NHibernate user, most likely you find advice to use a custom IInterceptor or IPreUpdateEventListener. Both are quite ugly solutions, since you have to manipulate the raw state values that are already read from the entity and are ready to be saved to the database. What's even worse, in the latter case you should sync it manually with the entity properties as well. One may think that the original code had been ported from Hibernate before IDictionary was invented (I do understand that there might be some excuses, like performance considerations for example). Find the index of the required field in one array, then fix the value at the corresponding index in another one. Oh joy!

So, it's quite understandable that I wanted a more elegant solution. Just "fix" the entity before being saved, and also do it in a more, well, object oriented fashion. Naturally this should happen just before the property values are read.

So, I put a breakpoint on a property getter and started the debugger. Turned out the property was read by an instance of NHibernate.Event.Default.DefaultFlushEntityEventListener, which leads me to believe that its OnFlushEntity method is what actually turns my properties into arrays of raw values. Further investigation showed that this listener is an element of an array of IFlushEntityEventListener-s. So, my plan (which, unsurprisingly, succeeded), was to put my custom implementation in this array before the default one.

Just show us the code! I hear you say. Ok, ok, I'm coming to that. Suppose you have a base entity class (but you're not quite sure, 'cause there might be some 3rd party entities floating around). You just add a template method to it called EnsureConsistency, or PerformAudit, whatever. Here is my custom listener:

public class CustomFlushEntityEventListener : IFlushEntityEventListener 
{
  public void OnFlushEntity(FlushEntityEvent @event) 
  {
    var entity = @event.Entity as EntityBase;
    if (entity != null) 
      entity.EnsureConsistency();
  }
}

Now you have your class, here is how to tell NHibernate it should use it (during application startup):

configuration.SetListeners(ListenerType.FlushEntity, 
  new IFlushEntityEventListener[]
  {
  new CustomFlushEntityEventListener(),
  new DefaultFlushEntityEventListener()
  }
);

Here "configuration" is an instance of NHibernate.Cfg.Configuration, and the code should be run before you build you SessionFactory. The result is, for each entity being flushed, its EnsureConsistency method is being called. The entity itself knows what to do (if anything) in this case. Audit, denormalization, whatever.

Now I do feel like a real Pro. Please tell me I am.


License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Artem Smirnov
Software Developer Freelancer
Russian Federation Russian Federation
No Biography provided

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Mobile
Web03 | 2.8.140814.1 | Last Updated 11 Jan 2011
Article Copyright 2011 by Artem Smirnov
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid