Requirements      
Prerequisite knowledge
Required products
Sample files User level
Familiarity with ColdFusion and database concepts will be helpful.
Adobe ColdFusion Enterprise Edition (2016 release) 8 (Download trial)
coldfusion9_orm_sample.zip (5 KB) Intermediate

 

Note: This article was created based on the ColdFusion 9 beta release. Minor changes in the description and code may be necessary before it can be applied to ColdFusion 9.
As the author of the Transfer framework, I have had a strong interest in ColdFusion Object Relational Mapping (ORM), and persistence frameworks in general for a fairly long time. When I heard that the ColdFusion 9 was going to include integration with Hibernate, one of Java's premier ORM frameworks, I was very interested in exploring the new capabilities that this was going to offer to a wide variety of ColdFusion developers.
I quickly found that the integration with Hibernate and ColdFusion has been delivered exceedingly well, hiding away many of the complexities of implementing Hibernate (and ORM in general), while still giving the developer remarkable flexibility in development strategies, and also exposing many of the layers of Hibernate to those who want to take direct advantage of some of its more complex and configurable features.
In this article, I'll provide a review of ORM in general as well as ColdFusion and Hibernate integration before covering how to perform database operations and manage relationships with ORM.

 
What is an ORM?

While the term Object Relational Mapper sounds complex and scary, at a core level, the concept is actually fairly simple and straightforward. The crux of the matter comes from the fact that in applications, objects know about each other through references in memory, while in a relational database, tables of data refer to each other through primary and foreign key relationships. For example, a Musician object may know about an array of Instruments he can play, but in the database a Musician table will have a primary key, which is referred to by a foreign key to build a relationship between a Musician and his Instruments.
The job of an ORM, then, is to translate objects into relational data and relational data into objects, without the developer having to do any of the hard work. While many ORMs have more features above and beyond this core tenet, at a basic level it really is nothing more complicated than that.

 
Why use an ORM?

The explanation of an ORM sounds very good academically, but what benefits can you expect to receive as a developer? Essentially, the major reason to use an ORM is to save you time when developing applications. While obviously it will always take time to first master a new tool, I think this point is so important, that I will say it again: An ORM will save you a lot of time when developing applications.
This includes reduced implementation time up front when first developing your application, since an ORM will save you from the hours of tedious drudgery that is writing create, read, update, and delete SQL statements and the ColdFusion code to go with them. Not only that, but an ORM will reduce the number of potential error spots in your application, since you have a single configuration point for all your persistence needs. With an ORM, having a correct INSERT statement, but a spelling mistake in your UPDATE statement tends to be a thing of past.
Maintenance time is also reduced. For example, if you wanted to add an extra property to your object, normally you would have to make changes in a myriad of places, from UPDATE, SELECT, and INSERT statements, to ColdFusion code. All of these changes introduce the possibility of making further programming errors. When using an ORM, it is usually one change in a single place, and that is all you need to do.

 
What is Hibernate?

To quote the Hibernate website, "Hibernate is a powerful, high performance object/relational persistence and query service." It is also one of the most popular Java persistence solutions currently in use.
Hibernate provides all the create, read, update, and delete (CRUD) tools you need to push and pull objects in and out of a relational database via a sophisticated mapping configuration. It also has tools for enhanced querying, generating your database schema, caching, event interception, and much more.
In the long term, it is definitely worth learning more about how Hibernate works so that you can begin to understand what ColdFusion is actually doing behind the scenes and get yourself out of some tricky gotcha situations. For now, however, you can get started with the ORM integration without knowing all of the details, because much of complicated work has been done for you by the ColdFusion developer team.

 
ColdFusion and Hibernate integration

Before ColdFusion 9, if you wanted to use Hibernate in a ColdFusion application, you had to be comfortable with either Java or Groovy. You also had to set it up yourself, and worry about Java classpaths, Hibernate configuration, Hibernate session management, transaction management, and all the little ins-and-outs that make Hibernate a wonderfully powerful, yet often complex piece of software to manage.
Now with ColdFusion 9, there is no need to learn Java or Groovy. Thanks to the Hibernate and ColdFusion 9 integration, many of these aspects are managed for you or provided to you in ways that you already understand. By using ColdFusion Components and an Application.cfc to use and configure the ORM, the average ColdFusion developer can now take advantage of the power and flexibility of Hibernate.
 
ORM configuration
The first step in configuring ORM integration is done through your application's Application.cfc.
To turn on ORM, include the line:
 
this.ormenabled = true;
Hibernate is now available to use.
Taking advantage of a new ColdFusion 9 enhancement, you can set a default data source for all <cfquery> calls in your Application.cfc by including the following line:
 
this.datasource = "orm";
This tells the application to use the orm data source, and also tells Hibernate which data source you want it to connect to.
Note: Hibernate integration can work with only one data source within a given ColdFusion application. Given the fact that Hibernate can only manage one database at a time, this restriction is not entirely surprising. This doesn't preclude you from accessing other data sources through <cfquery>, but it is a limitation that you should be aware of.
In terms of configuration, there is nothing else that you are required to do. There are, however, several other optional attributes that you can use to control how Hibernate works. These attributes are provided through this.ormsettings, which is a struct of optional values that are set in Application.cfc. In this example, I first tell the ORM that the CFCs I'm using are in the /com folder, so it doesn't search my entire webroot, and I get a faster startup.
 
this.ormsettings.cfclocation = "com";
I am also going to set the dialect that Hibernate is going to use, which tells the ORM what type of database it will be managing. Typically, you won't need to do this as it is configured automatically, but for this example I am using mySQL and I'm having Hibernate create my databases for me. Since I want Hibernate to create my tables as InnoDB, for transaction and foreign key support, rather than the default, MyIsam, I have to set this value.
 
this.ormsettings.dialect = "MySQLwithInnoDB";
I'm also going to use the dbcreate and logSQL settings, which I am only going to run on my development server.
Since I've decided that I want to have Hibernate create my database tables for me (allowing me to focus on creating the objects for my application), I have to tell it how I want it to do this. If I set dbcreate option to update, then it will create the table it needs if it doesn't exist, and attempt to update it if it already does. That being said, I actually like to start from a clean database with each restart of my application, so I know the exact set of data I use on each iteration. For this reason, I'm going to set it to dropcreate, so that Hibernate will drop the table if it already exists, and then recreate it:
 
this.ormsettings.dbcreate = "dropcreate";
Finally, I tell Hibernate to log all the SQL that it generates, for debugging purposes.
 
this.ormSettings.logSQL = true;
Unfortunately, this doesn't log SQL to the debug view like <cfquery>, but instead logs it to the console. This isn't such a problem if you are used to starting up ColdFusion via the command line, versus starting ColdFusion as a Windows Service, for example, but if you aren't, starting ColdFusion through ColdFusion Builder beta will give you access to the same information.
If you want to reload Hibernate, recreate tables, or reload the mapping configuration (which I'll cover shortly), you can do so with the ORMReload()method, which will reload the ORM without reloading the application. Alternatively, you can use ApplicationStop() to stop the application; on the next request the application, and hence the ORM, will also be reloaded. I've set up a utility to restart my application in Application.cfc:
Application.cfc
 
<cfcomponent hint="I am the Application CFC" output="false"> <cfscript> this.name = "ORM Demo"; //turn on orm this.ormenabled = true; this.datasource = "orm"; //add some additional settings this.ormsettings = { cfclocation = "com", dialect="MySQLwithInnoDB" }; //if this is a development server... this.developmentServer = true; if(this.developmentServer) { this.ormsettings.dbcreate = "dropcreate"; this.ormsettings.logSQL = true; } </cfscript> <cffunction name="onRequestStart" access="public" hint="Request start processing" returnType="boolean" output="false"> <cfargument name="targetPage" type="string" hint="The page requested" required="true"/> <cfif StructKeyExists(URL, "reload")> <cfset ApplicationStop() /> <cflocation url="#arguments.targetPage#"> <cfreturn false /> </cfif> <cfreturn true> </cffunction> </cfcomponent>
There are many more ORM configuration options available to use in Application.cfc that I haven't covered, but this is enough to get started. If you want to learn more, you can read ColdFusion 9 Developers Guide—ORM settings.

 
Performing CRUD with ORM

Performing basic create, read, update, and delete operations with ColdFusion 9's ORM integration is remarkably simple. Simply define a CFC with the properties that you want to use and store in the database, and let Hibernate do the rest of the work for you. For example, the following CFC represents a Musician, for whom I am going to store a name and an age:
 
Musician.cfc
 
<cfcomponent hint="I am a musician" output="false" persistent="true"> <cfproperty name="musicianID" hint="The id for the musician" type="numeric" fieldtype="id" datatype="integer" generator="identity"> <cfproperty name="name" hint="name of the musician" type="string" length="255"> <cfproperty name="age" hint="Age of the Musician" type="numeric" datatype="integer"> <cffunction name="init" hint="Constructor" access="public" returntype="Musician" output="false"> <cfargument name="name" hint="the name of the musician" type="string" required="no" default=""> <cfscript> setName(arguments.name); return this; </cfscript> </cffunction> </cfcomponent>
The first thing to note about this example is the persistent attribute on <cfcomponent>. When persistent is set to true, this tells ColdFusion that this CFC represents data in the database and that the data can be persisted through the ORM integration. I then take advantage of the new implicit getter and setter functionality by using <cfproperty> to specify what properties the Musician needs to have, which in this case is a musicianID, the name of the musician, and the musician's age. When the ORM starts up, it will now automatically create a database table named "Musician". Because I specified fieldtype="id", datatype="integer", and generator="identity", Hibernate will set an auto-incrementing numeric primary key of musicianID on the table. The columns "name" and "age" are also created, matching the <cfproperty> definitions that I have defined. On the name property, I've set the length to 255 by using the length attribute. On the age property, I've set the column data type to integer by using the datatype attribute (see Figure 1).
 
Figure 1. The Musician table.
Figure 1. The Musician table.
 
Since Hibernate is creating the database for me, I can take advantage of several default values that I don't need to change. For example, I don't need to specify a table name, as the table value is set to the name of the component, in this case, "Musician". So while it may seem like I haven't used many attributes to map the CFC to the database table, there are many more options available. To map an existing database structure, you would need to be more explicit and comprehensive about your mappings, and not rely on default values. From this point, things become really easy. To create a new musician you can use the following code:
 
<cfscript> import com.*; larry = new Musician("Larry Jingle"); larry.setAge(47); EntitySave(larry); </cfscript>
This code simply creates a new Musician object, sets some properties on it, and calls EntitySave(). This method will take the object it is passed and persist it in the database, without you having to write any SQL. It will even create the table for you (see Figure 1 and Figure 2).
 
Figure 2. Musician data.
Figure 2. Musician data.
 
To load Larry and change his age, you can use the following (see Figure 3):
 
<cfscript> //larry's ID is 1 larry = EntityLoad("Musician", 1, true); larry.setAge(48); </cfscript>
The first argument for EntityLoad() is the entity name of the CFC you want to load, which by default is the same name as the CFC, although this can be overwritten. The second argument is the id of the Musician you wish to load. To ask for a unique result, you have to specify true as the third argument, otherwise EntityLoad() will return an array rather than just a single value.
Note: EntityLoad() can be used to return arrays of CFCs, filtered by your criteria, but I won't be covering that in this article.
Note that the code did not explicitly tell Hibernate to update larry. Hibernate keeps track of what CFCs have been loaded and if they have changed from their initial state. In this case, it can see that the age property of Larry has changed, and at the end of the request it will update the database accordingly. You could call EntitySave() on Larry when you are updating him, but the call simply gets ignored by Hibernate when the object is already persisted in the database.
 
Figure 3. Larry is loaded and his age is changed.
 
Note: For performance reasons, Hibernate will generally batch execute its SQL at the end of the HTTP request. Therefore, even if you use EntitySave() in the middle of a code block, the insert SQL may not be actually run against the database until the end of the request. There are methods to force the SQL to be executed, which can be read about in ColdFusion 9 Developer Guide—Hibernate session management.
Finally, if you decide you don't need Larry anymore, you can delete him:
 
<cfscript> //larry's ID is 1 larry = EntityLoad("Musician", 1, true); EntityDelete(larry); </cfscript>
Larry is now no longer persisted in the database (see Figure 4).
 
Figure 4. Larry is deleted.
Figure 4. Larry is deleted.
 
You now have complete create, read, update, and delete functionality without having to write any SQL or create any tables. Hibernate and ColdFusion 9 have done all of that heavy lifting for you!

 
Managing relationships with ORM

Generally speaking, CFCs tend to work best not by themselves, but rather when there are groups of them that know about each other. For example, what would a Musician be without an array of Instruments to play?
There are a variety of relationship types that you can map with the ORM integration. In this article, I'll focus on a Musician having a many-to-many relationship with an Instrument, and allow Musicians to share Instruments within the group, so that multiple Musicians can have access to the same Instrument at the same time. This should give you enough of a start so that you can explore all the other relationship types that the ColdFusion Hibernate integration supports.
First, I set up an Instrument component just as I did with the Musician component:
Instrument.cfc
 
<cfcomponent hint="An instrument" persistent="true" output="false"> <cfproperty name="instrumentID" hint="id for the instrument" type="numeric" fieldtype="id" datatype="integer" generator="identity"> <cfproperty name="name" hint="The instrument name" type="string" length="255"/> <cfproperty name="noise" hint="the noise it makes" type="string" length="255"/> <cffunction name="init" hint="Constructor" access="public" returntype="Instrument" output="false"> <cfargument name="name" hint="the name of the instrument" type="string" required="no" default=""> <cfargument name="noise" hint="the noise it makes" type="string" required="false" default=""> <cfscript> setName(arguments.name); setNoise(arguments.noise); return this; </cfscript> </cffunction> </cfcomponent>
I also need to add a new <cfproperty> to the Musician to tell it about the array of Instruments it is about to get access to. I change the Musician.cfc code to look like this:
Musician.cfc
 
<cfcomponent hint="I am a musician" output="false" persistent="true"> <cfproperty name="musicianID" hint="The id for the musician" fieldtype="id" type="numeric" datatype="integer" generator="identity"> <cfproperty name="name" hint="name of the musician" type="string" length="255"> <cfproperty name="age" hint="Age of the Musician" type="numeric" datatype="integer"> <cfproperty name="instruments" hint="Array of instruments" singularname="instrument" fieldtype="many-to-many" collectiontype="array" cfc="com.Instrument" linktable="musician_instrument" FKColumn="musicianID" inversejoincolumn="instrumentID" orderby="name"> <cffunction name="init" hint="Constructor" access="public" returntype="Musician" output="false"> <cfargument name="name" hint="the name of the musician" type="string" required="no" default=""> <cfscript> setName(arguments.name); return this; </cfscript> </cffunction> </cfcomponent>
I have added a new <cfproperty> named instruments to define the new many-to-many collection. I set the fieldtype attribute to "many-to-many", and I set the cfc attribute to "com.Instrument", which is the CFC for items in the collection. The orderby attribute setting will sort all the Instruments by name in the array of Instruments.
Note: At the time of this writing, it is required to include the linktable, FKColumn, and inversejoincolumn attributes, to tell Hibernate what the linking table and foreign keys are. However, these attributes may become optional and have appropriate default values.
The code above creates the many-to-many table when the ORM is started, as well as a set of methods on the Musician that can be used to add and remove Instruments:
 
<cfscript> import com.*; john = new Musician("John Tunes"); john.setAge("51"); EntitySave(john); //we prepared some instruments earlier //a flute is instrument 1 flute = EntityLoad("Instrument", 1, true); //give John the flute john.addInstrument(flute); //a piano is instrument 2 piano = EntityLoad("Instrument", 2, true); //give john the piano john.addInstrument(piano); </cfscript>
In this case, the addInstrument() method gets its name from the singularname attribute set on the many-to-many configuration. To display all of John's Instruments you can use:
 
<cfoutput> John's Instruments: <br/> <cfloop array=#john.getInstruments()# index="instrument"> I am a #instrument.getName()#, and I make the noise #instrument.getNoise()# <br/> </cfloop> </cfoutput>
The code above would produce the output shown in Figure 5.
 
Figure 5: Output showing Musician John with two Instruments, a flute and a piano.
Figure 5: Output showing Musician John with two Instruments, a flute and a piano.
 
The Instrument, Musician, and musician_instrument tables shown in Figure 6 were created automatically.
 
Figure 6: Instrument, Musician, and musician_instrument tables
Figure 6: Instrument, Musician, and musician_instrument tables
 
After I added the piano and flute from the Instrument table (see Figure 7) to John, the musician_instrument table persists the relationships (see Figure 8).
 
Figure 7. Data in the Instrument table
Figure 7. Data in the Instrument table
 

Figure 8. Data in the musician_instrument table
 
Where to go from here

The ColdFusion Hibernate integration can greatly reduce the amount of work that you as a developer need to do to persist data when building applications, and the examples in this article only scratch the surface. Not discussed in this article are a wide variety of highly configurable functionality from Hibernate that has been brought into the ColdFusion product, including utilities for querying, caching, persistence event handling, and various other tools for managing application data. That being said, even using its most basic built-in ORM features can radically improve how quickly and effectively you develop ColdFusion applications.
To learn more about the ORM functionality in ColdFusion visit the following sites: