Sam Farmer head shot

Sam Farmer

Growing up I never imagined I would play bass guitar for the Dave Matthews Band. And indeed it never happened.

But I have become a passionate and pretty good web developer.


Using structures/maps instead of arrays in ORM

By default an ORM relationship is an array. Using a structure (map for non-ColdFusion programmers) is very easy and provides nice options. Lets start with a simple relationship between of users and addresses.


User.cfc

view plain print about
1component persistent="true" {
2property name="userId" fieldtype="id" generated="always" generator="native";
3property name="name" ormtype="string";
4
5property name="address" fieldtype="one-to-many" cfc="address" fkcolumn="userId" inverse="true";
6}


Address.cfc

view plain print about
1component persistent="true" {
2property name="addressId" fieldtype="id" generated="always" generator="native";
3property name="type" ormtype="string";
4property name="street" ormtype="string";
5property name="city" ormtype="string";
6property name="state" ormtype="string";
7
8property name="user" fieldtype="many-to-one" cfc="user";
9}


A single user object with two addresses would look like this:


Now, if we want to find out if the user has a work address we need to loop through getAddress(). Thats ok but by converting the relationship to a struct its possible to then use structure functions. Here is the relationship in User.cfc defined to return a structure:

view plain print about
1property name="address" fieldtype="one-to-many" cfc="address" fkcolumn="userId" inverse="true"
2    type="struct" structkeycolumn="type";


A dump of the user object now looks like:


Which means we can use code like this, in particular line 3:

view plain print about
1<cfset u = entityLoad("user")>
2<cfloop array="#u#" index="user">
3    <cfif structKeyExists( user.getAddress(), "work" )>
4        <cfdump var="#user.getAddress()["work"]#">
5    </cfif>
6</cfloop>


For reference here is the Application.cfc to set up Hibernate/ORM:

view plain print about
1component
2{
3this.name="structsDemo";
4this.ormEnabled=true;
5this.datasource="cfartgallery";
6this.ormsettings = { dbcreate="update" };
7
8}

Related Blog Entries

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
Hey Sam,

That's an excellent post thanks. I often forget that you can use structs for relationships, probably because I never really put much thought into the possible use cases for it.

This makes really great sense, and is an excellent approach.

Thanks,

Robert
# Posted By Robert Rawlins | 5/27/11 3:29 AM
One more thought:

Reading this does reawaken my desire for more intelligent collections in ORM entities other than just static arrays and structs. Something which makes searching and filtering the collection much simpler.

cfwheels has a great implementation, similar to that of Rails, where in your use case I wouldn't have to care about what collection we use (array vs. struct), nor would I have to run the structKeyExists(), I could search/filter the collection like so:

User.Address.findWhere(type='work');

I would love to see enhancements in the cf-orm implementation to do something like this.

Robert
# Posted By Robert Rawlins | 5/27/11 3:34 AM
@Robert Thanks.

The wheels/rails example is cool. In your example does that return just users who have a work address? And for those does it return there other addresses as well?

I think you can do something like this with HQL / ORMExecuteQuery()
# Posted By Sam Farmer | 5/27/11 8:20 AM
The problem is with 'struct' collection - if you have for example more than one "work" address (hypothetically) only last one will be loaded (probably all but first ones are overwritten). This is a big limitation for the projects I'm working on.
# Posted By Piotr Ignaczak | 10/27/11 9:30 AM
BlogCFC was created by Raymond Camden. This blog is running version 5.9.7. Contact Blog Owner