Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
I am the chief technical officer at InVision App, Inc - a prototyping and collaboration platform for designers, built by designers. I also rock out in JavaScript and ColdFusion 24x7.
Meanwhile on Twitter
Loading latest tweet...
Ben Nadel at CFUNITED 2010 (Landsdown, VA) with:

Learning ColdFusion 9: Exploring Object-Relational Mapping (ORM)

By Ben Nadel on
Tags: ColdFusion

I am calling this post an "Exploration" because I am not an authority on ORM by any means; in fact, this post was my first usage at any ORM framework, built-in or otherwise. As such, please take this entire post with a grain of salt. I am sure there will be many points where I am misunderstanding key concepts or fail to explain what is going on properly. To explore ColdFusion 9's new ORM framework (built on top of Hibernate), I decide to create a simple scenario in which we have only two objects:

  • Girl
  • Property

Each Girl instance (ex. Joanna) can contain a collection (0..N) of Property instances (ex. Athletic, Sassy, Sleazy). In this way, we will have a minor number of objects to think about but can still explore a large number of ORM features.

The whole point of using an ORM system is so that you don't have to think about the database at all; you think purely about Objects and the ORM system thinks about persistence and how those objects can be moved to the database tier. As such, I decided that I would not create a single database for this demo - I would simply define my objects and let the ORM system create the database tables for me. As someone who thinks very much about databases, this was both freeing and frustrating.

One of the upsides to letting the ORM system worry about the databases was that I could use ColdFusion's built-in Apache Derby database without having to deal with the fact that there is no provided interface for the Derby databases. Of course, regardless of what approach you are taking, you still need to create the database and a datasource for it in the ColdFusion administrator.

That all said, let's take a look at some code. Remember, because this is my first look into ORM, I will be defining a lot of things that probably don't need to be defined; I am explicitly defining attributes and settings that get defaulted so that I can gain a better understanding of what is going on. That said, ORM configuration begins with the Application.cfc:

Application.cfc

  • <cfcomponent
  • output="false"
  • hint="I define the application settings and event handlers.">
  •  
  • <!--- Define the application. --->
  • <cfset this.name = hash( getCurrentTemplatePath() ) />
  • <cfset this.applicationTimeout = createTimeSpan( 0, 0, 5, 0 ) />
  •  
  • <!---
  • Store the datasource for this entire application. This
  • will be used with all the CFQuery tags as well as by
  • the ORM system.
  • --->
  • <cfset this.datasource = "cf9orm" />
  •  
  • <!---
  • This will turn on ORM capabilities for this application.
  • This tells ColdFusion to load all of the Hibernate code
  • and to communicate with the datasource above to prepare
  • the configuration files.
  • --->
  • <cfset this.ormEnabled = true />
  •  
  • <!---
  • This will define how the ORM system will work. Because
  • we are not starting out with any database, but using the
  • ORM system to build the database, we want to turn off
  • the use of the DB to get mapping data - we will be
  • defining all of the mapping information in our CFCs.
  •  
  • NOTE: "None" is the default for dbCreate. I have left it
  • in here only because I am overriding it afterwards.
  • --->
  • <cfset this.ormSettings = {
  • dbCreate = "none",
  • useDBForMapping = false
  • } />
  •  
  • <!---
  • If the URL has the flag to rebuild the database, switch
  • the ORM settings to drop and recreate the database.
  • Obviously, this is something we don't really want to have
  • in our code, for my learning purposes, I have found this
  • to be a nice feature.
  • --->
  • <cfif !isNull( url.rebuild )>
  •  
  • <!---
  • Override the ORM settings to drop and create the
  • database for this request. This will destroy all
  • of our persisted data.
  • --->
  • <cfset this.ormSettings.dbCreate = "dropcreate" />
  •  
  • </cfif>
  •  
  •  
  • <!--- Define the request settings. --->
  • <cfsetting showdebugoutput="false" />
  •  
  • </cfcomponent>

The first two key things when working with ORM in a ColdFusion application is that you have to define the Datasource (this.datasource) and enable ORM using this.ormEnabled. Once you do this, when your application boots up, ColdFusion will build all the Hibernate configuration files and mappings by recursively traversing your application directories, looking for ORM-enabled ColdFusion components (this is explained later).

By default, the ORM system will not alter the database as it creates the configuration files. However, since our demo does not have any database tables to begin with (our Derby database starts out empty), we have to get the ORM system to flesh out our database based on our object definitions. As such, I am using a URL parameter, "rebuild," to trigger table creation. Specifically, I am using this.ormSettings.dbCreate to tell the ORM system to drop all the database tables and recreate them. I have chosen the drop/create approach since I am still learning all of this and I like being able to start fresh on a whim.

If you are only making minor changes to your model, you can set the this.ormSettings.dbCreate property to "update". This will create a table if it doesn't exist, or update is structure if it has been modified. Once your changes are done, however, you probably want to either exclude this property or default it to "none," which will not make any changes to the database (best performance).

As a final note on the Application.cfc, I am turning off the property this.ormSettings.useDBForMapping; since we have no database to begin with, it would be pointless for the ORM system to use the database to gather mapping information (ex. primary keys, data types).

Now that we have ORM turned on in our ColdFusion application, we need to look at the objects that we will use in our demo (and that will be used by the ORM system to define the database tables). Let's look at the Property.cfc first as it is the less complicated one:

Property.cfc

  • <!---
  • When defining the component class, set persistent to true.
  • This tells ColdFusion that this component is going to be an
  • ORM object.
  •  
  • Because I am not mapping the CFC name directly to the table
  • name, I am using the Table attribute to tell the ORM what
  • table to use for persistence.
  • --->
  • <cfcomponent
  • output="false"
  • persistent="true"
  • table="girl_property"
  • hint="I am a girl property object.">
  •  
  • <!---
  • Define the properties of the ORM component. These
  • properties are used to map the object properties to the
  • properties in the database table. Some of these properties
  • are used at configuration time, some of these properties
  • are used at runtime.
  • --->
  •  
  • <!---
  • This is the unique ID of the girl property. Because this
  • is a value that is generated by the database, I do not
  • want anyone to set it manually. As such, I am turning off
  • the setter() access to this property.
  •  
  • The fieldType "ID" flags this property as the primary key
  • for this entity. The generator "Identity" tells the data-
  • base how to generate the ID value (using its own identity
  • algorithm).
  • --->
  • <cfproperty
  • name="id"
  • type="numeric"
  • validate="integer"
  • setter="false"
  • hint="I am the unique ID of the girl property."
  •  
  • persistent="true"
  • fieldtype="id"
  • column="id"
  • ormtype="integer"
  • generator="identity"
  • length="10"
  • />
  •  
  • <!---
  • This is the name (description) of the entity. The
  • fieldType value of "Column" means that this is just a
  • standard column.
  •  
  • Since this column value is extremely important to the
  • working of the system, I have added a non-null constraint.
  • As such, I am not leaving a default value, since that
  • would allow a user to bypass the validateParams pattern.
  • --->
  • <cfproperty
  • name="name"
  • type="string"
  • validate="regex"
  • validateParams="{ pattern=.+ }"
  • hint="I am the name (description) of the property."
  •  
  • persistent="true"
  • fieldtype="column"
  • column="name"
  • ormtype="string"
  • length="50"
  • notnull="true"
  • />
  •  
  •  
  • <cffunction
  • name="init"
  • access="public"
  • returntype="any"
  • output="false"
  • hint="I return an initialized component.">
  •  
  • <!--- Define arguments. --->
  • <cfargument
  • name="name"
  • type="string"
  • required="false"
  • hint="I am the name property."
  • />
  •  
  • <!---
  • Store arguments into properties if they are present
  • in the argument collection.
  • --->
  • <cfif !isNull( arguments.name )>
  •  
  • <!---
  • Set name property. Notice that I am using the
  • implicit setter defined by the CFProperty tags
  • above.
  • --->
  • <cfset this.setName( arguments.name ) />
  •  
  • </cfif>
  •  
  • <!---
  • Return this object reference. Remember, when
  • using the NEW operator, ColdFusion returns the
  • value returned by this method.
  • --->
  • <cfreturn this />
  • </cffunction>
  •  
  • </cfcomponent>

First off, you will notice that I am not defining any methods other than the object constructor, Init(). Because we are using CFProperty tags, all of the appropriate getter and setter (access and mutator) methods are being defined for us implicitly by ColdFusion. But, I'm getting ahead of myself - let's start from the top, with the CFComponent tag. The CFComponent tag is where we tell the ORM system that this ColdFusion component is meant to be used as part of the domain model that will be persisted.

By setting persistent="true" in the CFComponent tag, we are essentially enabling ORM for this object. By default, the ORM system will create a datatable using the name of the CFC; but, for this CFC, I didn't want the names to line up (more for practice than practicality). As such, I supplied the Table attribute. By setting table="girl_property", I am telling the ORM system to store the Property instances into a table named girl_property.

For each of the CFProperty tags, I put a line break within the tag definition to separate what I considered the CFComponent aspects from the ORM aspects. Attributes like Name, Type, and Validate, which don't have anything to do with ORM, I put first. Then, I put ORM-specific attributes like Persistent, FieldType, and Column last (after the extra line break). I like this approach as it allows me to think in two different mind sets independently.

Of the non-ORM CFProperty attributes, notice that my ID property has defined setter="false." Since the ID value that we are using will be created by the database automatically, I didn't want anyone trying to set it manually. By setting setter="false", I am preventing ColdFusion from creating an implicit setter for this property. And, since this property is being generated by the database, I am not supplying any default value. The method by which the database will provide this ID value is defined by the Generate attribute.

The ORM system knows that this ID property is the primary key of the table because I am setting the FieldType to be "ID." For properties that are non-primary key in nature, I would either use the FieldType "column," or, in the case of relationships, something like "many-to-many."

By default, the ORM system will consider each CFProperty tag a column in the corresponding database table. Despite this default behavior, I am defining persistent="true" on each property (again, just to get a better handle on ORM). If you want your CFCs to have non-persisted properties, you simply have to set persistent="false".

For those properties that will be persisted (the default behavior), the Column attribute is used to define the name of the corresponding column in the database table and the ORMType attribute is used to define the type of data contained within it. The ORM system will do its best to map the ORMType to the correct underlying database column type; but, in cases where you want to fine tune the translation, you can use the SQLType attribute (shown in next CFC) to guide the ORM configuration.

As a final note on this ColdFusion component, understand that if your CFProperty does not define a default value, the property will be ColdFusion-NULL (undefined). As such, I thought it was a best-practice to provide a component constructor (init() method) to allow easy object creation in conjunction with mission-critical value setting.

Now that we have our Property.cfc ColdFusion component defined, let's look at the Girl.cfc ColdFusion component. Much of the CFProperty information here will be a repeat of what we saw above, so I won't bother explaining it; the biggest difference that we will explore is the fact that the Girl.cfc can contain a collection of Property.cfc's which means we need to define a relationship.

Girl.cfc

  • <!---
  • When defining the component class, set persistent to true.
  • This tells ColdFusion that this component is going to be an
  • ORM object.
  •  
  • I don't really need to use the Table attribute here since it
  • will default to the name of the CFC. However, as I am
  • learning, I am erring on the side of TOO much information.
  • --->
  • <cfcomponent
  • output="false"
  • persistent="true"
  • table="girl"
  • hint="I am a girl object.">
  •  
  • <!---
  • Define the properties of the ORM component. These
  • properties are used to map the object properties to the
  • properties in the database table. Some of these properties
  • are used at configuration time, some of these properties
  • are used at runtime.
  • --->
  •  
  • <!---
  • The ID of this object will be autogenerated by hibernate
  • (via the underlying database). Because this is a unique
  • ID, we don't want people to try to set it, therefore the
  • setter attribute is set to false (removing the implicit
  • setter method).
  •  
  • The fieldType "ID" flags this property as the primary key
  • for this entity. The generator "Identity" tells the data-
  • base how to generate the ID value (using its own identity
  • algorithm).
  • --->
  • <cfproperty
  • name="id"
  • type="numeric"
  • validate="integer"
  • setter="false"
  •  
  • persistent="true"
  • fieldtype="id"
  • column="id"
  • ormtype="integer"
  • generator="identity"
  • length="10"
  • />
  •  
  • <!---
  • This is the name of the girl entity. I have defined it as
  • not allowing NULL values. As such, we cannot define a
  • default value or someone might save an empty string.
  • --->
  • <cfproperty
  • name="name"
  • type="string"
  • validate="regex"
  • validateParams="{ pattern=.+ }"
  •  
  • persistent="true"
  • fieldtype="column"
  • column="name"
  • ormtype="string"
  • length="30"
  • notnull="true"
  • />
  •  
  • <!---
  • The isHot column is a boolean value. However, since the
  • Apache Derby database that we're using doesn't support
  • "boolean" data types, we are going to tell the ORM system
  • to use the datatype SMALLINT when persisting to the
  • Derby database (and when building the database table).
  •  
  • This column also has a not-null constraint, but I am OK
  • leaving a default value here since it's not a mission
  • critical value.
  • --->
  • <cfproperty
  • name="isHot"
  • type="boolean"
  • default="false"
  •  
  • persistent="true"
  • fieldtype="column"
  • column="isHot"
  • ormtype="boolean"
  • sqltype="smallint"
  • length="1"
  • notnull="true"
  • />
  •  
  • <!---
  • This is a collection of Property.cfc instances that
  • describe the girl. Because these properties are not
  • directly linked to this table, we must ust a JOIN
  • table. The FieldType of "many-to-many" tells the ORM that
  • this relationship needs a JOIN table to link the source
  • table to the target table.
  •  
  • The LinkTable attribute tells ORM what the name of the
  • JOIN table should be.
  •  
  • The FKColumn attribute tells ORM the name of the foreign
  • key in the join table that related back to THIS entity's
  • primary key.
  •  
  • The InverseJoinColumn attribute tells ORM the name of the
  • foreign key in the target table (girl_property) that links
  • back to the girl property table.
  •  
  • The Cascade attribute tells ORM how to save property
  • instances in this collection that have not yet been
  • persisted to the database. By using "Save-Update", we are
  • telling ORM that any unsaved Property.cfc instances here
  • should be persisted anytime the Girl.cfc instance is
  • persisted.
  • --->
  • <cfproperty
  • name="properties"
  • type="array"
  •  
  • persistent="true"
  • fieldtype="many-to-many"
  • cfc="Property"
  • linktable="girl_girl_property_jn"
  • fkcolumn="girl_id"
  • inversejoincolumn="girl_property_id"
  • lazy="false"
  • orderby="name ASC"
  • cascade="save-update"
  • />
  •  
  •  
  • <cffunction
  • name="init"
  • access="public"
  • returntype="any"
  • output="false"
  • hint="I return an initialized instance.">
  •  
  • <!--- Define arguments. --->
  • <cfargument
  • name="name"
  • type="string"
  • required="false"
  • hint="I am the name property."
  • />
  •  
  • <!---
  • Store arguments into properties if they are present
  • in the argument collection.
  • --->
  • <cfif !isNull( arguments.name )>
  •  
  • <!---
  • Set name property. Notice that I am using the
  • implicit setter defined by the CFProperty tags
  • above.
  • --->
  • <cfset this.setName( arguments.name ) />
  •  
  • </cfif>
  •  
  • <!---
  • Return this object reference. Remember, when
  • using the NEW operator, ColdFusion returns the
  • value returned by this method.
  • --->
  • <cfreturn this />
  • </cffunction>
  •  
  • </cfcomponent>

If I were to code the database for these two objects (Girl.cfc and Property.cfc), I would create a JOIN table for our many-to-many relationship. And, as much as we want to use ORM to get away from a data-centric mentality, when it comes to many-to-many relationships, we still have to specify some data table information. Specifically, we have to tell the ORM system what the JOIN table will be called and how the various primary keys will line up.

By setting the FieldType="many-to-many" and CFC="Property", we are telling the ORM system that this property will be a many-to-many collection of Property.cfc instances. The LinkTable attribute defines the name of the JOIN table used to relate the two sets of objects. Within the JOIN table, the Girl.cfc's primary key (ID) is related using the FKColumn attribute; the Property.cfc's primary key (also ID) is related using the InverseJoinColumn attribute. Together, the FKColumn and InverseJoinColumn attribute define the two columns of the JOIN table.

By default, the ORM system requires instances contained within a collection to be already-persisted when the parent object is persisted. However, in this demo, we're using the cascade="save-update" to allow non-persisted Property.cfc instances to be put in the collection. This way, when we save our Girl.cfc instance, the ORM system will cascade that "save" command down to all of the contained Property.cfc instances. If we did not provide this Cascade command, attempted to save non-persisted Property.cfcs within a Girl.cfc would raise an exception.

Phew! We have configured this ColdFusion application to use ORM and we have reviewed both of the ColdFusion components that we're going to be playing with. Now, let's actually do something with them:

  • <!---
  • Reload the hibernate configuration files. These are only
  • created / loaded when the application is first started up.
  • Therefore, if we are making any changes to the model or
  • to the ORM settings, we need to restart the application or
  • call ormReload(). I am doing this here only because I am
  • learning as I go and this keeps things fresh.
  •  
  • NOTE: Once your model is stable, you would NOT neet to have
  • any statements like this.
  • --->
  • <cfset ormReload() />
  •  
  •  
  • <!---
  • Create some properties. Because our properties are simple
  • objects, we can just loop over a list of values.
  • --->
  • <cfloop
  • index="propertyName"
  • list="Athletic, Plump, Brunette, Blonde"
  • delimiters=", ">
  •  
  • <!--- Create a new property instance. --->
  • <cfset property = new com.Property( propertyName ) />
  •  
  • <!--- Save the record. --->
  • <cfset entitySave( property ) />
  •  
  • </cfloop>
  •  
  •  
  • <!--- Create a new girl. --->
  • <cfset joanna = new com.Girl( "Joanna" ) />
  •  
  • <!---
  • Set the properties for this girl. This array of properties
  • will be based on the properties we created above. Therefore,
  • we have to load them based on name (as we didn't get any
  • handles on them).
  •  
  • The third argument, true, determines that this property is
  • unique. In doing so, it return the given instance rather than
  • an array of instances.
  • --->
  • <cfset athletic = entityLoad(
  • "Property",
  • { name = "Athletic" },
  • true
  • ) />
  •  
  • <cfset brunette = entityLoad(
  • "Property",
  • { name = "Brunette" },
  • true
  • ) />
  •  
  • <!---
  • Store the properties. Notice that we are referencing two
  • existing properties AND a completely new one. The new property
  • which is currently unsaved would throw an error except for the
  • fact that the Cascade value on this girl proprety is set to
  • "save-update", which will cascade save command down to the
  • properties collection.
  •  
  • NOTE: This is not typically done with many-to-many
  • relationships, but I wanted to do it here to see how it would
  • work.
  • --->
  • <cfset joanna.setProperties(
  • [
  • athletic,
  • brunette,
  • new com.Property( "Sassy" )
  • ]
  • ) />
  •  
  • <!---
  • Add a different property using the implicit ADD method. This
  • method is created for relationship-based properties.
  • --->
  • <cfset joanna.addProperties(
  • new com.Property( "Classy" )
  • ) />
  •  
  • <!---
  • Based on the above collection of properties, I think we can
  • safely set the hotness aggregate. Notice, of course, that this
  • is using the implicit setter created by the CFProperty tags.
  • --->
  • <cfset joanna.setIsHot( true ) />
  •  
  • <!--- Save the girl object with it's property associations. --->
  • <cfset entitySave( joanna ) />
  •  
  •  
  • <!---
  • Actually, you know what, let's remove the classy property
  • from the girl - it makes her a bit more interesting. Notice
  • that we are doing this using the implicit collection REMOVE
  • method that get's auto-generated for collections.
  • --->
  • <cfset joanna.removeProperties(
  • entityLoad( "Property", { name = "Classy" }, true )
  • ) />
  •  
  •  
  • <!---
  • For performance reasons, ColdFusion ORM batch executes
  • updates to the database. To force any updates to the
  • database, call ORMFlush(). If you don't do thi, ORMFlush()
  • is called at the end of each request by default.
  •  
  • We are calling this here because we are going to test the
  • EntityReload() function below which will need the database
  • to be updated first (as it re-queries the database).
  •  
  • NOTE: A new ORM session is created and flushed wihin each
  • CFTransaction tag.
  • --->
  • <cfset ormFlush() />
  •  
  •  
  • <!---
  • Reload the girl instance. This will refetch the data from
  • the database. We are doing thit to make sure the data can
  • be re-read properly.
  • --->
  • <cfset entityReload( joanna ) />
  •  
  • <!--- Ouptut the girl. --->
  • <cfdump
  • var="#joanna#"
  • label="Girl.cfc Instance (Joanna)"
  • />

Because I was doing a lot of experimentation with ORM for the first time, I called ORMReload() at the top of the page. This got the ORM system to rebuild the configuration files and mappings. Normally, you would NOT need to have this on your page.

I then created a number of new Property.cfc instances and a Girl.cfc instance. I wanted to move some of these properties into the girl, but because I didn't keep a handle on the properties I previously created, I needed to query them. Of course, since we are using ORM and not CFQuery, I needed to gather the target properties using EntityLoad(). Because I didn't know the IDs of the generated properties, I had to use the criteria struct containing the Name value of the given properties. By default, EntityLoad() will return an array of objects when using search criteria; however, we are telling EntityLoad() that these objects will be unique (the True parameter), which will get EntityLoad() to return a single instance rather than a collection.

Once we have our Property instances, we can move them into and out of the Girl instance in a few different ways. Because the Girl.cfc has a "Properties" property, we can use the implicit setter to store an array of property instances. But, because this collection is also defined as a relationship to another CFC, ColdFusion generated a few other methods used to add and remove instances from the collection. Specifically, we can now use addProperties() and removeProperties() to add and remove a given Property.cfc instance without having to get and re-set the entire collection.

Once I moved around all of these properties, I wanted to test the persistence aspect of the ORM system. Since the changes to the ORM are not flushed to the database until the end of the page request (or CFTransaction block), I am explicitly calling ORMFlush() to persist all changes. Then, once that is done, I repopulate my Girl.cfc instance with database information using EntityReload() and CFDump it out. This is the output we get:

 
 
 
 
 
 
ColdFusion 9's New ORM Functionality Allows Many-to-Many Collections. 
 
 
 

As you can see, our Girl.cfc contains a collection of Property.cfcs. Pretty snazzy! One thing that you might notice, however, is that the ID values of each object were successfully moved from the database identities into the appropriate ID properties. Normally, you might not give this a second thought; but, remember that we set setter="false" on these ID properties, preventing people from setting ID values into the CFCs. It looks like the ORM system is able to set private data (in the CFC's Variables scope) without having any direct access to it. This is a minor but very important point.

Wow - that's a lot of information to take in; and, it just barely begins to scratch the surface of ColdFusion 9's new ORM capabilities. I wanted to keep these posts short, but this one ended up being quite long. Hopefully, this post got a lot of the basics out of the way and future ORM-related posts can be more targeted and therefore much more succinct.



Looking For A New Job?

100% of job board revenue is donated to Kiva. Loans that change livesFind out more »

Reader Comments

This is some really cool stuff. Thanks for sharing. Once your database structure or objects become more complicated; do you think that this work just as well? Meaning using properties to define primary keys and relationships... I don't really have any experience with Hibernate, but I have played around with Transfer a little bit. What is your opinion on this?

Reply to this Comment

@Steve,

I don't really have an opinion just yet. This stuff is so new to me, I'm just trying to wrap my head around all of it. Hopefully in the next few blog posts, I'll try to explore some more complex aspects.

I think not thinking about the database is pretty cool.

Reply to this Comment

How come in girl.cfc, you say that the id property should not be set, but you have setter as true, or did you mean something else?

Reply to this Comment

@Rex,

Ahh, nice catch. Before I posted, I toggled back and forth between true / false to debug something. I forgot to set it back to "false" at the end.

Anyway, I updated the code; also ran it again locally to double-check that nothing changed. Still all the same. Thanks for pointing that out.

Reply to this Comment

As a database developer, I am a bit wary about an object oriented framework creating my relation databases. I am aware that the functionality can be turned off; however I have had too many discussions with application developers explaining to them that their databases are running poorly because they left them as an after-thought.

I am half-expecting the support forums to start filling with new CF developers ask for help with their objects running slowly, blaming CF and Hibernate, when it is actually an ORM based solution that has blown out, with the database structure only being updated by Hibernate.

I guess it comes down to some words from the wise: "With great power comes great responsibility".

On another note, I am curious to see how the CF ORM abilities stand up in the performance department.

Reply to this Comment

First of all, this is a nice post, Ben! You have given the correct perspective by saying that one needs to worry about objects and need not worry about the database/tables.

@Steve, ColdFusion-ORM has the ability to handle complex scenarios - all kinds of relationships (1-n, n-1, n-n, 1-1), component mapping, join mapping, inheritance mapping, computed properties, etc are supported.

@Andrew, Rupesh has written a nice post on the performance of ColdFusion-ORM - http://coldfused.blogspot.com/2009/07/coldfusion-orm-and-cfc-performance.html. Please go through that.

Reply to this Comment

Hi Manjukiran, that link appears to be broken for me. I am very interested in the performance aspect. For me - not having a fine bead on the DB tier for high-performance application is a worry to me. I used OJB (http://db.apache.org/ojb/) before with CF and it was a pretty inefficient implementation in places. With ditched it in the end.

For example: In regard to not thinking about the DB, what happens if, for example you want to add locking hints to all or some of your (MS SQL Server) SQL statements for performance reasons. Is there a way to ask the underlying Hibernate layer to do something like that? For example:

select * from customers (nolock) where customerID = 123

or

update customers with (rowlock) set name = 'bob' where customerID = 123

Thanks!

Reply to this Comment

Sorry about the broken link - http://coldfused.blogspot.com/2009/07/coldfusion-orm-and-cfc-performance.html (Its the '.' at the end of link which broke it :)).

Regarding lock stuff, I am copy/pasting my answer to a similar question from my blog:

1. ColdFusion-ORM can be used with the cftransaction tag along with different isolationlevels ("read_uncommitted | read_committed | repeatable_read"). They work the same way as they do for cfquery stuff. See the ColdFusion 8 livedocs for an explanation of the different isolation levels.

2. Versioning properties can be defined for every persistent component which is one more way to handle conflict resolution and concurrency.

3. The attribute "optimistic-lock" can be defined in the persistent component with value that can be set to all or dirty or version or none.

For a detailed explanation on Versioning and optimistic-lock please refer "Versioning" and "Transaction and Concurrency" topics in ColdFusion documentation -> "Developing Applications with Adobe ColdFusion 9.pdf->Chapter 8: ColdFusion ORM"

HTH

Reply to this Comment

@Ben, Nice post ! I am really looking forward for more posts from you on ORM. :-)
@Manju, you have given the links from my old blog which I plan to discontinue.
Here is the correct link
http://www.rupeshk.org/blog/index.php/2009/07/coldfusion-orm-and-cfc-performance/

@Steve, It is in fact much simpler. You can check out some other posts that cover ORM basics

http://www.rupeshk.org/blog/index.php/2009/07/coldfusion-orm-the-basics/

http://www.adobe.com/devnet/coldfusion/articles/coldfusion9_orm.html

Reply to this Comment

@Steve,

Like @Rupesh said, it actually is a bit simpler than I have outlined it. With things that I am very new to, such as ORM, I tend to provide more information than you would normally. For example, many of these attributes default to what I have explicitly set them. Persistent (on CFProperty), for example, defaults to True and I Column defaults to the name of the property. So, you could actually leave out a good amount of what I chose to put in.

But, until I get a better handle on how it all works, I like to err on the side of having TOO much context than too little. Once I get the basics connecting in my head, I'll probably leave out some of the information based on defaults.

Reply to this Comment

@Manjukiran, @Rupesh,

Thanks guys. The ORM stuff seems really interesting, just a completely different way of seeing things. It took me like 2 hours just to figure out how ORMReload() interacted with the dbCreate settings (my most recent ORM post).

Cool stuff, though - will be playing much more with it.

Reply to this Comment

Ben,
Thank you for so many great posts. This is a terrific one too, as it incerased my undersatnding from nill to something useful...almost...I can't get past an erro the code, as shown throws.
The error is
[Macromedia][SequeLink JDBC Driver][ODBC Socket][Microsoft][ODBC Microsoft Access Driver] Missing semicolon (;) at end of SQL statement.
Root cause :java.sql.SQLException: [Macromedia][SequeLink JDBC Driver][ODBC Socket][Microsoft][ODBC Microsoft Access Driver] Missing semicolon (;) at end of SQL statement.

The error occurred in C:\Inetpub\wwwroot\Garry\cfc\ORM\girl.cfm: line 28

26 :
27 : <!--- Save the record. --->
28 : <cfset entitySave( property ) />
29 :
30 : </cfloop>


I do not know what this is. I made the db in Access and saved it as an access .mdb file so CF could find it and it checked out ok in the cf admin. However, it looks to me like a conflict between the dialect and the actual db type. CF livedocs says to use mssqlserver as the flavor for access, so have you got any ideas?

thanks for your help in days past on so many topics.

Peace
Harry

Reply to this Comment

@Hbalzac,

How are you defining the database type in the Application.cfc ORM settings? I believe for MS Access, you have to define it as MS SQL Server.

Reply to this Comment

Hey man, thank you very much for this and all your blogs. Got a simple question for you that maybe has no answer. If I were to have a table that has the same name as an ORM reserved word, say, "component", how can I define ORM relationships associated with that table? Or is that impossible?

Reply to this Comment

when I try to run this sample, I have error:
Could not find the Coldfusion component or interface Property

I can't find out where the problem is. Any idea?

Reply to this Comment

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
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.