Sam Farmer

Growing up I never imagined I would play bass guitar for the Dave Matthews Band. And indeed it never happened.

But I have become passionate about making software.

Using ORM Event Handler to easily and automatically add audit information

January 23, 2010

Using the event handling features in ORM in ColdFusion 9 makes it easy to automatically add audit information such as last updated and last modified by to all objects, well technically tables, in the database.  I'm about to launch my first ColdFusion 9 application and the technique below has worked well and sped up development.

Step 1: Decide on audit colum names

There really is no right or wrong way here.  Go for something readable and easily understandable (for those lucky future developers who will look at your code!).  Once you pick them add them as properties to your CFC:

component persistent="true" {
property name="teamID" fieldtype="id" generator="native" generated="always";
property name="teamName" ormtype="string";
property name="dateCreated" ormtype="timestamp";
property name="dateModified" ormtype="timestamp";
property name="createdBy" ormtype="integer";
property name="lastModifiedBy" ormtype="integer";
}

Step 2: Turn on Event Handling and Hander

In your Application.cfc in addition to ormEnabled=true, turn on event handling and an event handler like so:

this.ormsettings = { eventHandling=true, eventHandler="myEventHandler" };

The eventHandler points to a valid CFC "myEventHandler.cfc" which is what we will create next.

Step 3: Create an Event Handler CFC (See I told ya!)

The event handler must implement CFIDE.orm.IEventHandler. CFBuilder makes this easy, add a new ColdFusion Component file and on the New ColdFusion Component screen under ‘Implements’ click on ‘Add’, and select CFIDE.orm.IEventHandler. If you script style components, as I do, click the ‘Generate Script Style Code’ option.
 
Your new file will look like this:
component implements="CFIDE.orm.IEventHandler"
{
         public void function preDelete( any entity)
         {
 
         }
         public void function preInsert( any entity)
         {
 
         }
         public void function preLoad( any entity)
         {
 
         }
         public void function postDelete( any entity)
         {
 
         }
         public void function postLoad( any entity)
         {
 
         }
         public void function preUpdate( any entity, Struct oldData)
         {
 
         }
         public void function postUpdate( any entity)
         {
 
         }
         public void function postInsert( any entity)
         {
 
         }
}

Step 4: Add code to preInsert and preUpdate functions

The preInsert and preUpdate functions in the event handler CFC are the last functions that get run before ColdFusion hands over to Hibernate for persistence (a fancy way of saying saving to database).  All of the functions in eventHandler take in the entity as an argument called entity (if you are new to cfscript within the parenthesis its saying a type of any and an argument called entity).  We simply call the various functions and pass in the values.  I found I got an error at first matching the session userID to createBy and lastModifiedBy and needed to use JavaCast.  [Update Feb 6 '10: This bug is scheduled to be fixed in 9.0.1] After making a change to myEventHandler.cfc run ormReload() (I've gotten used to having this in onRequestStart and commenting it out when not needed).

public void function preInsert( any entity)
{
     entity.setCreatedBy( JavaCast( "int", session.userID ) );
     entity.setLastModifiedBy( JavaCast( "int", session.userID ) );
     entity.setDateCreated( now() );
     entity.setDateModified( now() );
}

The preUpdate function is very similar except just has the setLastModifiedBy and setDateModified calls.  If all your entities don't have the audit properties/columns use this technique for checking if the function exists.

Lets see it in action.

Using the Team object from above:

<cfset t = entityNew( "Team" )>
<cfset t.setTeamName( "Arsenal" )>
<cfset entitySave( t )>

Thats all the code needed.  Here's a screenshot of the database after insert that shows all the audit data.

Database with Audit Information


No Comments

Some comments have been lost over the years due to moving hosts.

More


More blog entries that I have written.

Code coloring by PRISM.