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:
... and when I look at the database, I get these records:
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)>
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.
Want to use code from this post? Check out the license.