Over a million developers have joined DZone.

Some recent ColdFusion ORM Pain

DZone's Guide to

Some recent ColdFusion ORM Pain

· Web Dev Zone
Free Resource

Add user login and MFA to your next project in minutes. Create a free Okta developer account, drop in one of our SDKs to your application and get back to building.

I'm working on a relatively simple ColdFusion ORM application. It is focused around a core entity type called Content. This entity type is rather large, around 50 or so properties. As you can imagine, some of the properties are simple, some are many-to-one, and some are many-to-many. I ran into some very frustrating issues though and I thought I'd share them.


The first issue I ran into was a bit of code I used to set a set of simple values. I've got a bunch of values that don't (really) need any validation and can simply be copied from a structure directly into the entity. So I created a simple list and iterated over it to set my values.

var simpleList = "subsegment,topic,topicupdatedby,task,need";

for(var x=1; x lte listLen(simplelist); x++) {
	var li = listGetAt(simpleList, x);
	invoke(content, "set#li#", data[li]);

Simple, right? But note the use of invoke. This is a ColdFusion 10 addition that lets you call dynamic methods in CFCs. I noticed that none of my data was actually persisting. Why?

Turns out - in order for my calls to setX (where X is a entity method) to work, I have to pass the value as a structure. Here is the modification:

for(var x=1; x lte listLen(simplelist); x++) {
	var li = listGetAt(simpleList, x);
	invoke(content, "set#li#", {"#li#"=data[li]});

Why? I've got no freaking clue. To be fair, the docs show passing a structure of arguments, but they don't explicitly state that you must do this. Even worse, an error was never thrown when I passed the argument as a simple value instead. I hate errors that are ignored.

Error Reporting

The second issue was much, much worse. Not that it was difficult to fix once I knew what the issue was, but the problem was in how the issue was reported.

As I mentioned above, my entity has simple properties, many-to-one properties, and a many-to-many. I began by coding in the simple properties (using the technique I described above). I then did my many-to-one. I then did the many-to-many.

I noticed that my join table was not populating. I didn't get an error though. What makes this more frustrating was that I could dump my entity before the save operation and clearly see my related data in the entity. Yet I'd run the save, it would insert a new record into the core table, and just... do nothing else. Again - no damn error. Anywhere.

So I backed up a bit. First I decided - let's turn off the auto flush feature and use transactions. I didn't think that would help per se, I just decided to give it a try. All of a sudden I got something - an error:

coldfusion.orm.PersistentTemplateProxy cannot be cast to java.util.Collection

Ok... so.... first off. Why would ColdFusion persist the entity, have a problem, and just not report it until I started handling the flush myself with a transaction? I can't imagine any reason why that would make sense.

Here's where things got even more interesting. I commented out the code handling the many-to-many and I still got the error!

On a whim, I decided to comment out the code handling 3 of my many-to-one properties. All of a sudden, that fixed the issue. I then uncommented out the many-to-many and it still worked fine (and persisted data to the join table). So obviously my issue was in the many-to-one blocks.

When you work with relationships, you're supposed to ensure you set both sides of a relationship. You can sometimes get by without, but you really shouldn't. In order to make this simpler, you can simply use some custom code in the core entity and have it do both sides of the relationship. So for example, here is one of those methods:

public any function setSegment(id) {
	var segment = entityLoadByPk("segment", id);
	variables.segment = segment;
	writelog("added a segment");

Simple, right? In my content entity I call setSegment. The method handles the logic of translating an ID to an entity, setting it, and doing the reverse side. But something in here was wrong.

At no time, though, was I told what was wrong. Outside of the error message I pasted above, I was lost.

Finally I started commenting the lines in that method and got it down to this:


And then it hit me. On the content side, it has one segment. On the segment side, it has many content entities.

So right away I've learned that the built-in methods are apparently not validating for the cases when an array is required.


Launch your application faster with Okta’s user management API. Register today for the free forever developer edition!


Published at DZone with permission of Raymond Camden, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}