Using ORM Event Handler to easily and automatically add audit information

ColdFusion 9, ORM

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

tarekac said:
 
Hi, how can you tell which object has been changed and what type of operation was performed, update/write etc?
 
posted 56 days ago
Add Comment Reply to: this comment OR this thread
 
Mike Henke said:
 
Pretty Cool. I need to play with the ORM in CF9. CFWheels ORM uses any table column named createAt, UpdateAt, and deletedAt through conventions.

http://cfwheels.org/docs/chapter/automatic-time-st...
http://cfwheels.org/docs/chapter/soft-delete
 
posted 55 days ago
Add Comment Reply to: this comment OR this thread
 
samfarmer said:
 
@tarakec: ColdFusion/Hibernate will work out what operation is going to be performed and then run the applicable function. Does that help?
 
posted 55 days ago
Add Comment Reply to: this comment OR this thread
 
Ben Nadel said:
 
I really don't like that you are required to use JavaCast(). That does not sit well with me. I was reading the other day someone else was having issues that were resolved with JavaCast(). Typically, I've accepted that JavaCast() might need to be used with a Query, but that's because it's just a specialized object. This seems too "vanilla" CF to have to use JavaCast()... grumble grumble :)
 
posted 55 days ago
Add Comment Reply to: this comment OR this thread
 
samfarmer said:
 
@Ben: I agree. I logged a bug...go vote for it! :)

http://cfbugs.adobe.com/cfbugreport/flexbugui/cfbu...=81941
 
posted 47 days ago
Add Comment Reply to: this comment OR this thread
 
samfarmer said:
 
Got verification that the bug will be fixed for 9.0.1
 
posted 43 days ago
Add Comment Reply to: this comment OR this thread
 
Pedro Claudio said:
 
Very good work...
Just be careful with the EntitySave into event... can generate loop ...

I like this ...



 
posted 30 days ago
Add Comment Reply to: this comment OR this thread
 
samfarmer said:
 
@Pedro: Good point!
 
posted 27 days ago
Add Comment Reply to: this comment OR this thread
 

Search

Twitter
You should follow me on Twitter here
About Me
I am a 34-year old Web Developer specializing in ColdFusion. I live and work in downtown Washington, DC with my wife and two daughters. Read more About Me

2007 CFeMmy Best Newcommer winner
As voted on by fellow CF Bloggers.