Learning ColdFusion 9: When Does An ORM-Enabled Object Get Persisted

Posted July 31, 2009 at 6:53 PM by Ben Nadel

Tags: ColdFusion

From what I have seen so far, the ColdFusion 9 ORM / Hibernate integration is very interesting. During my exploration of this feature, however, I ran into a persistence behavior that definitely confused me at first. From my initial read of the ORM documentation, I had thought that all matters of persistence were controlled by the EntitySave() method. As it turns out, though, this is not true - once an object has been persisted, all future updates to that object are automatically persisted after the Hibernate session ends (at request / transaction termination) or when the ORM updates are flushed manually.

 
 
 
 
 
 
 
 
 
 

On further reading of the various ORM blog posts out there, it seems that this is the correct behavior. But, since it confused me, I figured I would share my experience with others who might, at first, not understand what's going on. To test the ORM persistence behavior, I set up three simple ColdFusion pages that all interact with a single entity in a different way.

New ORM-Enabled Object

The first page that I wrote simply created a new object and stored some default data:

  • <h1>
  • ColdFusion 9 ORM: New Object
  • </h1>
  •  
  •  
  • <!---
  • Create a new Task object, passing some default values
  • to the object constructor.
  • --->
  • <cfset task = new com.Task(
  • "Ask Joanna to a movie.",
  • "Gather the courage and just ask her out!"
  • ) />
  •  
  • <!--- Output the new, non-persited task. --->
  • <cfdump
  • var="#task#"
  • label="New Task"
  • />
  •  
  •  
  •  
  • <!---
  • Check to see if are exiting out of the page. This is
  • here to see if new instances are saved without explicitly
  • calling entitySave().
  • --->
  • <cfif isNull( url.save )>
  • <cfexit />
  • </cfif>
  •  
  • <br />
  •  
  • <!--- Save the task. --->
  • <cfset entitySave( task ) />
  •  
  • <!--- Output the updated, persisted task. --->
  • <cfdump
  • var="#task#"
  • label="Saved Task."
  • />

As you can see, the code above can run in two different modes. If I run it without any URL flags, the new Task.cfc instance will be created but the template will exit without EntitySave() getting called. I did this to confirm that new objects would not be persisted without explicit ORM interaction. And, in fact, if I run this code as above, no record gets stored in the database.

If, however, I run the code with the URL parameter, "save," then EntitySave() does get executed, the CFC gets persisted, and a new record is stored in the database. This confirms the documented information that a new object will not be persisted until EntitySave() is explicitly called on it.

Existing ORM-Enabled Object

The second page that I wrote simply loads an existing object based on its primary key and outputs it:

  • <h1>
  • ColdFusion 9 ORM: Existing Object
  • </h1>
  •  
  •  
  • <!---
  • Load an existing task based on it's primary key.
  • Unlike entityLoad(), the entityLoadByPK() method
  • loads by primary key and returns a given instance,
  • not an array of matching instances.
  •  
  • NOTE: If no matching task is found, a null value
  • is returned.
  • --->
  • <cfset task = entityLoadByPK( "Task", 1 ) />
  •  
  • <!--- Output the existing task information. --->
  • <cfdump
  • var="#task#"
  • label="Existing Task"
  • />

This page is just here to help test what data is available after the following page has been run.

Updating An Existing ORM-Enabled Object

The third and final page that I wrote loads an existing ORM-enabled object and updates one of its properties:

  • <h1>
  • ColdFusion 9 ORM: Update Object
  • </h1>
  •  
  •  
  • <!---
  • Load an existing task based on it's primary key.
  • Unlike entityLoad(), the entityLoadByPK() method
  • loads by primary key and returns a given instance,
  • not an array of matching instances.
  •  
  • NOTE: If no matching task is found, a null value
  • is returned.
  • --->
  • <cfset task = entityLoadByPK( "Task", 1 ) />
  •  
  • <!--- Flag this task as having been completed. --->
  • <cfset task.setIsComplete( true ) />
  •  
  • <!--- Output the existing task information. --->
  • <cfdump
  • var="#task#"
  • label="Existing Task"
  • />

What you'll notice here is that while I am updating the IsComplete property of the Task.cfc instance, I am at no time executing an EntitySave() call. But, when I jump back over to the "Existing" ORM-Enabled object page, I get this output:

 
 
 
 
 
 
ColdFusion 9 ORM-Enabled Objects Will Automatically Persist Updates If The Object Has Previously Been Persisted. 
 
 
 

... and when I look at the database, I get these records:

 
 
 
 
 
 
ColdFusion 9 ORM-Enabled Objects Will Automatically Persist Updates If The Object Has Previously Been Persisted. 
 
 
 

As you can see, even without calling EntitySave(), updates to an already-persisted object are automatically persisted at the end of the Hibernate session (defined implicitly in this case as the end of the page request).

When I first read through the ORM documentation, it gave me the impression that all ORM-based persistence to the database needed to be done through explicit calls to the EntitySave() method. In fact, on the "Perform create, read, update, delete operations on ORM Objects" page of the CF9 Developer's Guide, it explains object updates as:

The method to update an object is the same as saving an object. Load the object that needs to be updated, make updates, and save the object. For example:

<cfset artist1 = EntityLoad("Artist", 1, true)>
<cfset artist1.setFirstName("Garcia")>
<cfset EntitySave(artist1)>

I think from something like this, it's easy to see where I would get my initial impressions. That's why the behavior I was seeing was so confusing. As it turns out, however, once an object has been persisted, any further updates to it will be automatically persisted at the end of the associated Hibernate session.


You Might Also Be Interested In:



Reader Comments

Jul 31, 2009 at 8:22 PM // reply »
24 Comments

It should also be noted Ben - to update an object, you actually don't have to call EntitySave() at all!

Have a look at my examples from my DevNet article:
http://www.compoundtheory.com/?action=displayPost&ID=417

In the update example, we don't even called EntitySave().

This is because the Hibernate Session is already aware of the object, and will track any changes that are made to the object.


Jul 31, 2009 at 8:23 PM // reply »
24 Comments

Oh wait.. you knew that. I didn't read your post properly.

Oops.

Ignore me!

* crawls under rock *


Jul 31, 2009 at 11:55 PM // reply »
45 Comments

This would make for a nice demo at the next NYCFUG.


Aug 1, 2009 at 11:27 PM // reply »
9 Comments

Would this work equally on any RDBMS?

MSSQL and MySQL don't require any type of COMMIT command be issued before a row is officially updated, where Oracle does (or at least it did when I last worked with it).

Will CF9's ORM implementation handle this transparently?


Aug 2, 2009 at 6:07 PM // reply »
10,638 Comments

@Mark,

No worries :)

@David,

Yeah, agreed. Perhaps we'll do some CF9-specific features in the upcoming months. That would be awesome.

@Claude,

As far as I know, this should all be handled transparently. Of course, I'm very new to this, so that is just my *assumption*.


Aug 3, 2009 at 2:00 AM // reply »
5 Comments

I can say that even the first ColdFusion page you presented had helped me in my work! I am not talking about other pages that are great


Aug 3, 2009 at 3:16 AM // reply »
54 Comments

This new ORM stuff is really very cool, this is what I think I consider the 'killer feature' in CF9 which will coax me into upgrading, really enjoying watching you guys explore it.

I wonder, has anyone yet done any performance testing on persisting / retrieving large record sets using the ORM features? I'd be keen to know how it shapes up compared to traditional methods, would give a good insight into those planning to use it in high-demand applications.

Rob


Aug 3, 2009 at 4:57 AM // reply »
1 Comments

@Claude: Both MySQL, MSSQL and Oracle can be configured (and are be default ?) to 'auto commit' without an explicit 'COMMIT;' statement (in it's own CFQUERY) as far as I know.
Certainly last time I used Oracle I didn't need to issue one.


Aug 3, 2009 at 9:03 AM // reply »
29 Comments

Whoa, this is actually a big deal when considering validation approaches. I had played around with CF9's ORM capabilities awhile ago and did not notice this behaviour. Do you know, is there a way to change this behaviour, so that an object is only saved when EntitySave() is called? Perhaps something one does with the object, or a hibernate configuration setting?


Aug 3, 2009 at 10:13 AM // reply »
10,638 Comments

@Bob,

It's funny you mentioned that because when I noticed this behavior, that was the very first thing that popped into my mind. I have seen *many* people populate a CFC just to validate it; it appears that that mentality can no long exist? I'll wait for some more ORM-experts to drop in on this, but I had the same reaction.


Aug 3, 2009 at 12:19 PM // reply »
38 Comments

Hi Ben, that is a great point that Bob raised about letting an entity validate itself. I had a look into and my response was too long to add here so I posted it here:
http://www.aliaspooryorik.com/blog/index.cfm/e/posts.details/post/cf9-orm-clearing-the-session-cache-227


Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
InVision App - Prototyping Made Beautiful With Prototyping Tools Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
Feb 3, 2012 at 10:49 PM
How I Got Node.js Running On A Linux Micro Instance Using Amazon EC2
Wow this was really helpful! Only thing I would add is you need to update your .bash_profile after you edit the secure_path. This is what I did: $ . ~/.bash_profile Otherwise, NPM won't be found. ... read »
Feb 3, 2012 at 10:14 PM
Pushing Base64-Encoded Images Over HTML5 WebSockets With Pusher And ColdFusion
@Ben, Just wanted to let you know that pusher are soon to start limiting sizes on messages. This was the detail that came through in the Feb dispatch: "However, we will soon be limiting the s ... read »
Feb 3, 2012 at 5:05 PM
Regular Expressions Make CSV Parsing In ColdFusion So Much Easier (And Faster)
I tried using your RegEx in my C# program, but it was matching an extra empty-string at the end and so I would end up with an extra field that doesn't exist, so I changed it to this: (^|,)("(?: ... read »
Feb 3, 2012 at 3:47 PM
ColdFusion Supports HTTP Verbs PUT And DELETE (As Well As GET And POST)
Josh Cyr posted this on Twitter just a little bit ago. Thought it was appropriate. http://stackoverflow.com/questions/1619152/how-to-create-rest-urls-without-verbs/1619677#1619677 ... read »
Feb 3, 2012 at 2:28 PM
Changing The Execution Context Of Your Self-Executing Function Blocks In JavaScript
@Michael, You definitely make a good point (and extra points for quoting movies - I love movies). When you use a return() statement to define the object's public API, it does provide a consistent a ... read »
Feb 3, 2012 at 2:04 PM
Changing The Execution Context Of Your Self-Executing Function Blocks In JavaScript
To quote Jurassic Park: "Just because you can doesn't mean you should". I completely, utterly disagree with the thought that this is more readable. Consider the current module pattern: if ... read »
Feb 3, 2012 at 1:10 PM
REST API Design Rulebook By Mark Masse
@Jordan, Yeah, WRML was created by Mark Masse (author of the book). I also found it to be a bit convoluted. I suppose it is intended to allow the Client to be able to programmaticaly respond to cha ... read »
Feb 3, 2012 at 1:08 PM
ColdFusion Supports HTTP Verbs PUT And DELETE (As Well As GET And POST)
@Jason, To be honest, I don't have good answers for that kinds of stuff. And, to the point, that is specifically why I *really* liked the REST API Design Rulebook by Mark Masse - he just cuts throu ... read »