Now that the Hibernate integration in ColdFusion 9 has been in use for a while, we're seeing an increasing number of questions on the CF-ORM mailing list. This isn't surprising, Hibernate is a vast topic in and of itself, and the CF documentation can really only scratch the surface. There are entire books just dedicated to using Hibernate (my personal favorite being Java Persistence with Hibernate).
It's one thing to look at the documentation and understand the simple use cases, but quite another to actually get into real world application development with Hibernate. With this in mind, I'm going to be posting a few blog entries that explore using CF and Hibernate in some more complex scenarios.
The end result will be a rudimentary blog application, and I'll post that code in the last blog entry on this topic. But before we get to that, I want to back up and look at how one might approach the design of this application.
Here is a simple UML diagram of the domain model I want to create:

Contrary to good OO design, I'm not focusing on the behavior of these objects at all due to the fact that this is specifically an ORM example. I am also making the following assumptions, which affected the way the associations were defined, and will drive some later decisions when it comes to loading the objects:
- A BlogEntry will typically be associated with a few BlogCategories (between one and four, but maybe a few more)
- A large number of BlogEntries (hundreds or thousands) can be associated with a BlogCategory
- A low to moderate number of BlogComments can be associated with a BlogEntry (probably up to a few dozen unless the entry triggers an unusual number of comments)
- Each entity should keep track of when it was created and who created it
With this in mind, the relationships are defined as follows:
- One User can be associated with many Entities via the createdBy property
- One BlogCategory can be associated with many BlogEntries
- Many BlogComments can be associated with a BlogEntry
- One BlogEntry can be associated with a BlogComment
Translated into code, the entities look like this:
component displayname="Entity" output="false" mappedsuperclass="true" accessors="true"
{
property name="id" fieldtype="id" type="numeric" ormtype="int" generator="native";
property name="dateCreated" type="date" ormtype="timestamp";
property name="createdBy" fieldtype="many-to-one" cfc="User" fkcolumn="createdBy";
}
component displayname="User" extends="Entity" persistent="true"
output="false" accessors="true"
{
property name="name" type="string" ormtype="string";
}
component displayname="BlogEntry" extends="Entity" output="false"
persistent="true" accessors="true"
{
property name="title" type="string" ormtype="string";
property name="content" type="string" ormtype="text";
property name="categories" singularname="category" fieldtype="many-to-many"
cfc="BlogCategory" linktable="entry_category"
fkcolumn="entryId" inversejoincolumn="categoryId";
property name="comments" singularname="comment" fieldtype="one-to-many"
cfc="BlogComment" fkcolumn="entryId"
orderby="dateCreated ASC" inverse="true";
BlogEntry function init()
{
variables.categories = [];
variables.comments = [];
return this;
}
}
component displayname="BlogCategory" extends="Entity" output="false"
persistent="true" accessors="true"
{
property name="name" type="string" ormtype="string";
}
component displayname="BlogComment" extends="Entity" output="false"
persistent="true" accessors="true"
{
property name="content" type="string" ormtype="text";
property name="blogEntry" fieldtype="many-to-one"
fkcolumn="entryId" cfc="BlogEntry";
}
As you can see, this is really a tiny amount of code when you consider everything that is going on under the hood. This gives me a solid basis for the application. I can create these objects, set properties and associations, and persist them to the database. But that's the easy part. I want to go further than the simple use cases.
In the upcoming entries, I'll look at how to best handle the bi-directional association between BlogEntry and BlogComment, as well as how to automatically set the createdBy and dateUpdated properties in Entity. I'll also be taking an in-depth look at using HQL for filtering, sorting, and optimizing the way the objects are created to eliminate unnecessary database queries.
Comments (6) |
del.icio.us
|
Digg It!
|
Linking Blogs
| 6531 Views

# Posted By Andrew Scott | 9/10/10 12:53 AM
Brian - two things.
one, I noticed that you are using accessors="true" on an Entity. What is the reason for this, I was under the impression that this is normail behaviour for Entities.
Second, you are creatin an init and usgin 2 variables to an empty array. Can you explain a bit why you ar doing that?
# Posted By Brian | 9/10/10 8:45 AM
Hi Andrew, I got in the habit of specifying accessors="true" because it is NOT the default for non-persistent CFCs. So for the sake of consistency I just set it all the time.
I'm setting up the two empty arrays because by default those properties will be null. Which means if I want to do something to those collections, I need to set them up. Make sense? This will probably make more sense when I post the third entry on handling the bi-directional relationship, since I'll be manipulating those collections directly before anything is persisted.
# Posted By Andrew Scott | 9/10/10 9:17 AM
Brian that is what I thought on both counts, but just wanted to clarify that.
# Posted By PB | 6/6/12 10:55 AM
Hi,
Is it necessary for a sub-class to have at least one property in addition to or overriding a property in the base class?
Thanks,
# Posted By Brian Kotek | 6/6/12 11:34 AM
It might. I know at one point there were issues with entities that were empty, but I actually haven't checked it for a while to see if that's still the case.
# Posted By PB | 6/6/12 11:58 AM
Thanks, Brian. I did check this today and it still seems to be the case.