EntityToQuery does not return a ColdFusion Query
Last week I was working on an ORM enabled application where I was returning an array of Product objects. Working with objects is great, however I wanted a feature on my product listing page that allowed the user to filter products by price range. Now I could do a simple fixed banding, but really the price bands should be determined by the products I'm displaying. Simple I thought, instead of doing another lookup to the database, I'd use EntityToQuery and then do a Query of Queries on the result to find the most expensive product and the least expensive product.
When I tried to do somthing like this:
<!--- get product objects as an array --->
<cfset products = ORMExecuteQuery( "from Product" )>
<!--- convert to a query so we can re-query the result without calling the database again --->
<cfset qProducts = EntityToQuery( products )>
<!--- get the max and min price to build dynamic price filter --->
<cfquery name="qPriceRange" dbtype="query">
SELECT Max( sellingcost ) as highestCost, Min( sellingcost ) as LowestCost
FROM qProducts
</cfquery>
<!--- carry on and loop through products array and display... -->
I got the error:
java.lang.ArrayIndexOutOfBoundsException
After dumping out the query to make sure the columns existing and scratching my head a few times I posted my frustration on twitter and Ben Nadel asked me what the underlying java type was being used. Sure enough a standard ColdFusion Query returns:
coldfusion.sql.QueryTable
whereas a query returned from EntityToQuery has a java type of:
coldfusion.orm.EntityQueryTable
So, it does seem that you can't use Query of Query with EntityToQuery which is a real shame!
- Posted in:
- ColdFusion
- Hibernate


Comment by Raymond Camden – June 22, 2010
Comment by Rupesh Kumar – June 22, 2010
Comment by John Whish – June 22, 2010
WriteDump(CreateObject('java','coldfusion.org.EntityQueryTable'));
Comment by David Boyer – June 22, 2010
qProducts = JavaCast('coldfusion.sql.QueryTable', EntityToQuery( products ) );
I have not tried it, but I think it would work. Unless coldfusion.orm.EntityQueryTable adds something that it just cannot work without.
Comment by Jason Dean – June 23, 2010
Also, did anyone try that JavaCast() approach? I am very curious to see if that works.
Comment by Ben Nadel – June 23, 2010
JavaCast type coldfusion.sql.QueryTable must be one of the following types: byte, char, short, int, long, float, double, boolean, string, bigdecimal, their corresponding array representation (eg : int[]), or null.
Comment by John Whish – June 23, 2010
I wasn't sure the JavaCast function would work. I remembered the error messages it's given me when I type integer instead of int. Java lets you do something called "Upcasting" www.codeguru.com/java/tij/tij0070.shtml
/>
Just not sure how we'd manage this in Coldfusion.
Comment by David Boyer – June 23, 2010
artists = EntityToQuery(EntityLoad("ARTISTS"));
WriteOutput('Artists: ' & artists.getClass().getName());
WriteDump(artists);
artists2 = artists.getShallowCopy();
WriteOutput('Artists2: ' & artists2.getClass().getName());
WriteDump(artists2);
Comment by David Boyer – June 23, 2010
help.adobe.com/en_US/ColdFusion/9.0/CFMLRef/WSc3ff6d0ea77859461172e0811cbec22c24-7fbe.html
/>
The indenting was screwed up on these list items
-xxx[]?where xxx is one of the following:
-any of the preceding types, except for null
-a Java class name
All I saw was "A java class name"
So if it were going to work, you'd have to ask for an array of said items. But it seems it only works for simple types, i.e. int[] String[]. So I don't think you'd be able to do "coldfusion.sql.QueryTable[]"
Later in the docs, I found this:
"JavaCast cannot be used to cast between complex objects, nor to cast to a super-class."
Comment by Jason Dean – June 23, 2010
Comment by Ben Nadel – June 23, 2010
getShallowCopy() did turn it into the right type but I think it's missing some extra metadata that QoQ's need.
Comment by David Boyer – June 23, 2010
Coming to the problem with EntityQueryTable, it has some metadata missing that is required for it to work in QoQ. And AFAIK, there is no workaround for this and you will have to wait for the updater.
Comment by Rupesh Kumar – June 23, 2010
Comment by Jamie Krug – June 23, 2010
If anyone is interested to get the max and min costs I did:
prices = ListToArray( ValueList( myQuery.sellingcost ) );
maxprice = ArrayMax( prices );
minprice = ArrayMin( prices );
Comment by John Whish – June 23, 2010
That will be much more neat and more efficient than doing all this.
You can simply use
ORMExecuteQuery(SELECT Max(p.sellingcost) as highestCost, Min(p.sellingcost) as LowestCost
FROM Product)
Comment by Rupesh Kumar – June 23, 2010
ORMExecuteQuery("SELECT Max(p.sellingcost) as highestCost, Min(p.sellingcost) as LowestCost
FROM Product as p")
Comment by Rupesh Kumar – June 23, 2010
I'm a big fan of HQL and that's what I'm using to get the products. BTW I like using "select new map( Max(p.sellingcost) as highestCost, Min(p.sellingcost) as LowestCost ) FROM Product as p" so that I don't get an array of arrays back.
There were two reasons why I didn't do that in this instance. Firstly, the products array is filtered by a lot params being passed in (category / brand / price range etc) so I didn't really want to have to have maintain and pass in the same arguments. The second reason was that I was trying to avoid hitting the database.
Comment by John Whish – June 23, 2010
Comment by Bob Silverberg – July 14, 2010
Comment by Ben Nadel – July 14, 2010
Thanks for this post. Its saved me twice.
Curt
Comment by Curt Gratz – December 30, 2010