• Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
    Dedicated community for Japanese speakers
  • 한국 커뮤니티
    Dedicated community for Korean speakers
Exit
0

Strange Behavior When Working with Nested Query Objects

Contributor ,
Feb 12, 2014 Feb 12, 2014

Copy link to clipboard

Copied

I just posted a comment over on Ben Nadel's site about this issue but I wanted to get some feedback from my fellow ColdFusion developers to see if anyone else has ever experienced this issue:

I have a function within a CFC that creates a query object and then nests another query object inside it (masterQuery > subQuery). The CFC returns the query object and to make things easier I loop through the query columns and bring everything into the local VARIABLES scope using the following format: "#a#" = masterQuery["#a#"] where "a" is the name of the query column.

After I had all of the query columns in the VARIABLES scope I tried to run a QofQ on the subQuery and low and behold I got an error message:

"coldfusion.sql.QueryColumn cannot be cast to coldfusion.sql.QueryTable"

However, when I tried a different method for bringing the masterQuery columns to the VARIABLES scope, I was able to get it to work: "#a#" = evaluate('masterQuery.#a#')

After doing some playing around using GetMetaData().getName() to determine what ColdFusion was seeing when a variable was set using masterQuery["#a#"] vs evaluate('masterQuery.#a#') I learned that ColdFusion continues to see the variable as a type: "QueryColumn" instead of its actual type (string, query, array, struct, etc...).

Currently the only way I can get CF to recognize the proper type is to use the evaluate() function.  What's even more annoying is that you can't reference columns in the nested query so masterQuery.subQuery.TestColumn1[2] produces an error message.

I wonder if this a bug within ColdFusion 10. I haven't tested it in any earlier versions and after extensive searching I couldn't find anyone else with a similar problem. Regardless I thought it was pretty interesting and noteworthy.

If you want to see some sample code to generate this error for yourself, here it is:

http://pastebin.com/pBkjUtxc

  1. <!--- start by building a new query object --->
  2. <cfset masterQuery = QueryNew("ID,Name,SubQuery", "INTEGER,VARCHAR,OBJECT")>
  3. <!--- add a row and some basic data --->
  4. <cfset QueryAddRow(masterQuery)>
  5. <cfset QuerySetCell(masterQuery, "ID",1)>
  6. <cfset QuerySetCell(masterQuery, "Name", "Dave")>
  7.   
  8. <!--- create a new sub query --->
  9. <cfset subQuery = QueryNew("TestColumn1,TestColumn2","VARCHAR,VARCHAR")>
  10. <!--- lets add a few rows to the subQuery --->
  11. <cfloop from="1" to="3" index="b">
  12.       
  13.         <!--- new row --->
  14.         <cfset queryAddRow(subQuery)>
  15.       
    1.     <!--- subQuery data --->
  16.         <cfset QuerySetCell(subQuery,"TestColumn1","Hello World")>
  17.         <cfset QuerySetCell(subQuery,"TestColumn2","All Your Base are Belong to Us")>
  18.       
  19. </cfloop>
  20. <!--- populate the master query column "subQuery" with the new query object we created --->
  21. <cfset QuerySetCell(masterQuery, "SubQuery", subQuery)>
  22. <!--- dump the data so we can make sure it looks good --->
  23. <cfdump var="#masterQuery#">
  24. <!--- now loop through the query, and assign all of the columns in the query to the variables scope --->
  25. <cfloop list="#masterQuery.columnList#" index="a">
  26.         <cfset "VARIABLES.#a#" = masterQuery["#a#"]>
  27. </cfloop>
  28. <!--- this generates an error in CF 10 (maybe other versions) --->
  29. <cftry>
  30.     <!--- try and run a QofQ --->
  31.     <cfquery dbtype="query" name="getSubQuery">
  32.     SELECT *
  33.     FROM subQuery
  34.     </cfquery> 
  35.   
  36.     <cfdump var="#getSubQuery#">
  37.     <cfcatch type="any">
  38.         <cfdump var="ERROR: #cfcatch.Message#">
  39.     </cfcatch>
  40. </cftry>
  41. <!--- Now try using evaluate() instead.  This doesn't generate an error for some reason --->
  42. <cfloop list="#masterQuery.columnList#" index="a">
  43.         <cfset "VARIABLES.#a#" = evaluate('masterQuery.#a#')>
  44. </cfloop>
  45. <!--- run the QofQ again --->
  46. <cfquery dbtype="query" name="getSubQuery">
  47. SELECT *
  48. FROM subQuery
  49. </cfquery>
  50. <cfdump var="#getSubQuery#">

Message was edited by: Henweigh99

TOPICS
Advanced techniques

Views

921

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Contributor ,
Feb 12, 2014 Feb 12, 2014

Copy link to clipboard

Copied

I think I may have solved my own issue... possibly. 

After doing more research I stumbled upon another Ben Nadel article:
http://www.bennadel.com/blog/214-Using-The-ColdFusion-Query-Object-As-A-Complex-Object-Iterator.htm

In this article it mentions some complications when trying to reference complex objects within queries.

What I was missing in my pastebin code when trying to assign a variable to a column in the query was the bracket notation designating the desired row.  I guess you have to do this when referring to complex object types.

So:

<cfset "VARIABLES.#a#" = masterQuery["#a#"]>

Should read:

<cfset "VARIABLES.#a#" = masterQuery["#a#"][1]>

Boom. Magic.

Hope this helps other people if they find themselves in a similar predicament.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Feb 13, 2014 Feb 13, 2014

Copy link to clipboard

Copied

Henweigh99 wrote:

So:

<cfset "VARIABLES.#a#" = masterQuery["#a#"]>

Should read:

<cfset "VARIABLES.#a#" = masterQuery["#a#"][1]>

Could be better, much better! The following are just string assignments:

<cfset "VARIABLES.#a#" = masterQuery["#a#"][1]>

<cfset "VARIABLES.#a#" = evaluate('masterQuery.#a#')>

They contain a lot of complexity for the sake of complexity! A variable assignment would have been much better.

Let us therefore dissect the code. Consider the loop you reference:

<cfloop list="#masterQuery.columnList#" index="a">

        <cfset "VARIABLES.#a#" = evaluate('masterQuery.#a#')>

</cfloop>

Assume that the columnList consists of "col1,col2,col3". Also assume that the query returns the following data:

      col1 | col2 | col3

row 1: v11 | v12 | v13

row 2: v21 | v22 | v23

row 3: v31 | v32 | v33

row 4: v41 | v42 | v43

Then the loop will run 3 times, since columnList has 3 elements. The attribute index="a" implies that the variable a will successively take the values "col1", "col2", "col3" at each pass of the loop. The value of "VARIABLES.#a#" will therefore be, successively, the strings

"VARIABLES.col1"

"VARIABLES.col2"

"VARIABLES.col3"

Likewise, the variable evaluate('masterQuery.#a#') will take on the respective values

evaluate('masterQuery.col1')

evaluate('masterQuery.col2')

evaluate('masterQuery.col3')

These are, by default, the values of the first row of each column, hence:

v11

v12

v13

So, what your loop actually does is as follows:

First pass: 

     "VARIABLES.col1" = v11

Second pass:

     "VARIABLES.col2" = v12

Third pass: 

     "VARIABLES.col3" = v13

You are essentially picking out the values of the first row! It would have been much simpler, and neater, to do something like this instead:

<cfset firstRowData = structNew()>

<cfloop list="#masterQuery.columnList#" index="a">

        <cfset firstRowData = masterQuery[1]>

</cfloop>

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Contributor ,
Feb 14, 2014 Feb 14, 2014

Copy link to clipboard

Copied

LATEST

Thanks so much for the tip and the detailed breakdown BKBK!  That's what I love about this forum, I always learn something new with each visit.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Resources
Documentation