I have been doing a ton of work lately with the ORM features in ColdFusion 9. Last night I was reading through my grails book and I came across a feature that I really like. In grails you can automatically have the date created (on insert) and last updated (on update) time stamp added to each table during their respected events. This way you always know when records were created and updated. We can replicate this feature on the entity itself or on all entities in our system and today I will show you how to do both.
First off you need to setup some settings in our application. You need to first setup your normal ORM settings like orm enabled and the data source. In the ORM settings we are going to be working with event handling and event handler. Event handling is false by default and therefor will not broadcast these events that we want to listen for. Also the db create setting must be set to update unless we already have these fields added to our table. Next we are going to create a very basic persistent entity in our model folder called User. As you can see this is no different from most of the entity's you have been building. The only difference is we are going to add 2 fields to our domain model. The date created and last updated should both be set to time stamps.
Now that we have event handling turned on and our entity ready we can work on adding the functionality I talked about at th e beginning of this article. As I said before we can listen for events on a per entity basis or application wide. First let us take a look at how we would do it on our user entity. Below is a list from the docs of the different methods we can listen for in our entity.
- preLoad(): This method is called before the load operation or before the data is loaded from the database.
- postLoad(): This method is called after the load operation is complete.
- preInsert(): This method is called just before the object is inserted.
- postInsert(): This method is called after the insert operation is complete.
- preUpdate(Struct oldData): This method is called just before the object is updated. A struct of old data is passed to this method to know the original state of the entity being updated.
- postUpdate(): This method is called afterthe update operation is complete.
- preDelete(): This method is called before the object is deleted.
- postDelete(): This method is called after the delete operation is complete.
This to me is awesome because its one less thing I have to manually worry about. I know that every time a record is inserted or updated we will have time stamps on them. This is great for the example I gave above but you will quickly find yourself asking the following. I have x number of objects in my system and I would really rather not have to do this to each of my entities. Your in luck because you don't have to and I am going to show you how!
You can define an application wide event handler for your app. First we are going to use all of the settings we did before but we are going to add one to the mix, eventhandler. Event handler is the path to your application wide event handler component (without the .cfc on the end, it knows that already).
Next we need to create our event handler component. The only requirements of this component is that it implements the CFIDE.orm.IEventHandler interface. When you implement an interface you must define each and every method in the interface. I find it much easier if you use the component wizard in builder and allow it to create all of the methods for you.
Now that we have our event handler in place and ready to go we need to write the code for our methods. When an application wide event is broadcasted the entity is passed along as an argument so we know which entity we are working with. That is all we need to add this functionality to every event.
As you can see this is a a pretty awesome use case for event handling but why stop there. You could record information about the user who made the changes to the database, copy versions to a version history table and even use the updates as some sort of restore point for your application. I am loving the cool things I can add to my app with very little coding and I hope you are starting to see the value in them as well.

#1 by Luis majano on 12/23/09 - 9:03 AM
keep it up your orm posts are awesome
#2 by Dan Vega on 12/23/09 - 9:09 AM
#3 by Terrence Ryan on 12/23/09 - 9:10 AM
#4 by Dan Vega on 12/23/09 - 9:40 AM
public void function preInsert(any entity){
if(propertyExists(arguments.entity,"dateCreated")){
arguments.entity.setDateCreated(now());
arguments.entity.setLastUpdated(now());
}
}
private boolean function propertyExists(entity,property){
var properties = getMetadata(arguments.entity).properties;
var exists = false;
for(i=1; i <= arrayLen(properties); i++){
if(properties[i].name == arguments.property){
exists = true;
break;
}
}
return exists;
}
#5 by Tony Nelson on 12/23/09 - 9:45 AM
#6 by Tony Nelson on 12/23/09 - 9:48 AM
Why not use structKeyExists(arguments.entity,"setDateCreated")? Much faster. :)
#7 by Dan Vega on 12/23/09 - 9:51 AM
#8 by Raymond Camden on 12/23/09 - 9:58 AM
#9 by Tony Nelson on 12/23/09 - 9:58 AM
Also, I believe you could've used arrayFindNoCase(getMetadata(arguments.entity).properties,property) rather than looping the over the array.
#10 by Tony Nelson on 12/23/09 - 9:59 AM
#11 by Dan Vegas on 12/23/09 - 10:07 AM
private boolean function setterExists(entity,method){
var functions = getMetadata(arguments.entity).functions;
var exists = false;
for(i=1; i <= arrayLen(functions); i++){
if(functions[i].name == arguments.method){
exists = true;
break;
}
}
return exists;
}
#12 by Sam Farmer on 12/23/09 - 10:33 AM
Whats also cool is that you can use both the eventhandler cfc and event handling in the entity cfc. In this case the pre/post functions are called first in the entity cfc and then in the eventhandler cfc.
#13 by Dan Vega on 12/23/09 - 10:35 AM
#14 by Dan G. Switzer, II on 12/23/09 - 10:48 AM
I recommend *not* using now(), but instead rely on a timestamp that will be consistent across the page request.
For example, with the code:
public void function preInsert(){
this.setDateCreated(now());
this.setLastUpdated(now());
}
The DateCreated & LastUpdated values can end up being milliseconds off. This can cause problems down the road if you're ever trying to do something like "where DateCreated = LastUpdated" to find records that have never been updated.
I recommend using a timestamp that is created on the page request, that way you insert the same timestamp for all database operations.
I've spent a lot of time tracking bugs in applications in the past where the problem stemmed from developers using the now() function with various insert/updates and expecting the timestamp to be equal amongst operations.
#15 by Sam Farmer on 12/23/09 - 10:52 AM
@Dan V: Thanks for putting my point into clearer English.
#16 by Dan Vega on 12/23/09 - 10:54 AM
tstamp = now()
this.setDateCreated(tstamp);
this.setLastUpdated(tstamp);
#17 by Henry Ho on 12/23/09 - 2:07 PM
#18 by Ben Nadel on 12/29/09 - 7:00 PM
Solid point. Could you also create a local variable to the update function that contained the date, then used that in both sets? Same concept, but locally scoped.
@Dan V.,
Awesome post; as the others say, keep it up.
#19 by existdissolve on 3/2/10 - 5:14 PM
#20 by Bernhard Döbler on 6/27/11 - 6:10 PM
have you seen a component implementing CFIDE.orm.IEventHandler written in tag notation? I just setup a small example and kept getting an error "... is not a valid ORM event handler." I replaced my CFC in tag notation with your CFC in script notation and it worked instantly.
#21 by Dan Vega on 6/27/11 - 6:58 PM
It should work regardless of syntax so something has to be wrong with the tag version. If you want to send it to me offline I can probably take a look at for you.
#22 by Dan Vega on 6/29/11 - 10:17 AM
http://groups.google.com/group/cf-orm-dev/browse_t...