Photo from Chile

ColdFusion 9.0.1 Now Available - With ORM Goodies

ColdFusion 9.0.1 is now available for download at http://www.adobe.com/go/getcf901, and, in addition to fixing a number of issues with ColdFusion 9.0, it's packed full of goodies as well. The details of all the new features can be found in the New Feature Notes, and the bug fixes and outstanding items can be found in the Release Notes. I think my favourite single new feature is the ability to do a for - in loop with an array, as looping through an array using script has always been a pain. I'm also very happy with some of the improvements to ORM. Here's a high-level summary of the new features, followed by some details on the ORM changes:

  • Language enhancements - including for-in loops for arrays.
  • New script functions implemented as CFCs - including dbinfo, imap, pop, ldap, and feed.
  • Caching enhancements - including the ability to get a handle on the ehCache session.
  • Support for IIS 7
  • ColdFusion Ajax enhancements - including updates cfmap, cfgrid, file uploading and JavaScript functions.
  • ORM enhancements - more details below.
  • Amazon S3 support - the ability to use Amazon S3 storage with most tags and functions that use a file or directory as input or output.
  • Various other enhancements covering areas such as Spreadsheets, AIR Integration, Flash Remoting, Blaze DS, Solr, Logging, Server Monitoring, and more.

ORM Enhancements

Here's a summary of the ORM enhancements in ColdFusion 9.0.1, followed by some details about each one:

  • Support for Multiple Datasources
  • Transaction Management Improvements
  • skipCFCWithError Flag in ormSettings
  • mappedSuperClass Attribute for Components
  • Use EntityNew to Populate a New Entity
  • Support for HQL in cfquery

Support for Multiple Datasources

In ColdFusion 9.0, you could only use the ORM with one datasource across an entire application. Now you can have as many datasources as you like. In a multiple datasource application you tell each persistent cfc which datasource to use via the datasource attribute of the component. You can define ormSettings individually for each datasource in your application using a structure. For example, assuming with have datasources called Bob, Dan and Ezra, and we want each of those to have a different value for the dbcreate ormSetting, we would specify that like so, in our Application.cfc:

view plain print about
1this.ormSettings.dbcreate = {
2    Bob = "dropcreate",
3    Dan = "update",
4    Ezra = "none"
5}

You can use that format for the schema, catalog, dialect, dbcreate and sqlscript ormSettings.

ColdFusion supports multiple ORM datasources by creating a new Hibernate Session for each datasource. One of the implications of this is that related cfcs must use the same datasource. That is, all cfcs that have relationships defined with one another must use the same datasource. Another implication of this is that, within a transaction, you may only modify entities within a single datasource. You can read in entities from another datasource inside the transaction, but if you attempt to modify entities belonging to different datasources within a single transaction an error will be thrown.

Because, in a multiple datasource application, you will now have multiple Hibernate sessions, many of the existing session management functions have been enhanced to allow you to specify which session to affect, by specifying the datasource name. The following functions now accept a datasource name, which is only applicable if you are using multiple datasources:

  • ORMGetSessionFactory
  • ORMGetSession
  • ORMCloseSession
  • ORMClearSession
  • ORMFlush
  • ORMEvictQueries
  • ORMExecuteQuery

In addition, the following functions were added that affect all Hibernate sessions in the request:

  • ORMCloseAllSessions
  • ORMFlushAll

Transaction Management Improvements

In ColdFusion 9.0, there was a serious issue, in my opinion, with the way the Hibernate session was managed during transactions. ColdFusion would flush and close an existing session when you started a transaction, and would also close an existing session when a transaction ended, whether via a commit or a rollback. This has been improved in ColdFusion 9.0.1. Now, by default, when you start a new transaction, any open sessions are flushed, but they are not closed, so they are available to be used within the transaction. As well, when a transaction completes, the session is no longer closed. If the transaction was committed the session is flushed, and if the transaction is rolled back the session is cleared.

I say above that this is the new default behaviour, as you can have even more control over when flushing happens by using the new automanageSession ormSetting. The default value is true and results in the above behaviour. If you set automanageSession to false, however, ColdFusion will only flush the session when a transaction commits. It will neither flush nor clear a session automatically in the other scenarios (i.e., when a transaction starts or is rolled back). For this reason running with automanageSession="false" is my preference, as it gives me the greatest amount of control.

skipCFCWithError Flag in ormSettings

This flag can be set to true (the default is false) to ignore any syntax errors in cfcs when ColdFusion is searching for persistent cfcs when the application starts or the ORM is reloaded.

mappedSuperClass Attribute for Components

You can now create a base (non-persistent) object which has properties, and then extend that object with other persistent objects, which will then inherit those properties. For example, let's say that every object in my system should have an auto-generated primary key called id and a dateCreated property. I could create a base object and a user object like so:

view plain print about
1component mappedSuperclass="true" hint="This is Base.cfc" {
2    property name="id" fieldtype="id" generator="native";
3    property name="dateCreated" ormtype="timestamp";
4}
5
6component persistent="true" extends="Base" hint="This is User.cfc" {
7    property name="firstName";
8    property name="lastName";
9}

The above mappings would give me a User object with four properties: id, dateCreated, firstName and lastName.

Use EntityNew to Populate a New Entity

You can now pass a structure into the EntityNew function, as an optional second argument, and it will use the key-value pairs to populate the properties of the object. For example, assuming we have the User object mapped as above, we could call EntityNew like so:

view plain print about
1user = EntityNew("User",{
2    dateCreated = Now(),
3    firstName = "Bob",
4    lastName = "Silverberg"
5});

The above code will return a new User object to me, with the dateCreated, firstName and lastName prepopulated with the values from the structure.

Support for HQL in cfquery

Rather than having to build an HQL statement using string concatenation, you can now construct your HQL statement inside a cfquery tag, similar to what you do for SQL queries. For example, to return all Users from our User table with a first name of Bob, we could write the following code:

view plain print about
1<cfquery name="Users" dbtype="hql">
2    from User where firstName = <cfqueryparam value="Bob">
3</cfquery>

One thing to note about the above code is that it will return an array of User objects, not a query.

All in all I think this is an excellent release and I applaud the Adobe ColdFusion team for their efforts and their responsiveness to the ColdFusion community.

TweetBacks
Comments
Nice post Bob. Thanks for including the release notes, which incidentally aren't very easy to find on the official release page.
# Posted By Bucky Schwarz | 7/13/10 12:07 PM
Nice post Bob, thanks! As a former student of your CF9 ORM training, I was looking forward to seeing if they implemented many of the features we learned and later agreed were needed. Particularly happy about the Transaction Management Improvements.
# Posted By Jim Pickering | 7/13/10 1:38 PM
Wow, these are some very welcome enhancements to ORM, especially the ability to assign multiple data sources in one application. That alone was a dealbreaker for me in about 50% of my applications.
# Posted By Kerr | 7/13/10 1:50 PM
Is it possible to perform a query-of-queries against the result of entityToQuery() now?
# Posted By Antony | 7/13/10 9:36 PM
@Antony: Yes, that problem has been fixed in the updater. You can now do a query-of-queries on the result of an entityToQuery().
# Posted By Bob Silverberg | 7/13/10 9:51 PM
@bob - brilliant, thanks for letting me know
# Posted By Antony | 7/13/10 10:53 PM
Great post Bob, Thanks for the tips.
# Posted By Thomas | 3/18/11 2:23 PM
I know it's most probably not possible...but maybe somebody found a way around.

I like to dynamically change the name in the datasource attribute of the component:

let's say in develoment mode I use use "dbDEV" and in production "dbPROD"?

it's a pitty to have my second database hardcoded in the component.
# Posted By Daniel | 4/24/12 12:01 PM
@Daniel: I don't believe it is possible, but you may want to ask at http://groups.google.com/group/cf-orm-dev.
# Posted By Bob Silverberg | 4/24/12 12:50 PM