在Coldfusion 9中使用coldfusion.sql.QueryTable.next()

时间:2011-07-06 17:16:10

标签: coldfusion coldfusion-9

我正在尝试编写一个自定义标记,它将以特殊方式迭代cfquery对象。我找到了这个页面:http://www.zrinity.com/developers/mx/undocumentation/query.cfm概述了如何使用底层的java方法来导航结果集,但它似乎不适用于CF9。

我可以很好地致电.next().previous().first().last(),每个方法都会更新query.currentRow,但会引用query.columnName始终返回第一行的值,而不是currentRow。

示例:

<cfquery name="testQuery" datasource="source">
  SELECT FooName FROM NumberedFoos
</cfquery>

<cfloop from="1" to="3" index="i">
  <cfoutput>#testQuery.currentRow# =&gt; #testQuery.fooName#</cfoutput><br />
  <cfset testQuery.next()>
</cfloop>

产地:

1 => Foo 1
2 => Foo 1
3 => Foo 1

我知道我可以使用像testQuery.fooName[testQuery.currentRow]这样的东西,但这对于我为自定义标记制作的人来说是非常不受欢迎的。上述链接中描述的功能是否已从CF9中删除?如果有,还有其他选择吗?

修改

为了扩展原因,客户需要一个自定义标记,允许它们“断言”查询的某些内容。客户端对CF的理解水平很低,但是编写SQL非常可靠。他们期望的最终结果类似于:

<cfquery name="purchaseTotals">
  SELECT PurchaseId, Total FROM Purchases
</cfquery>

<CF_ASSERT query="purchaseTotals">
  purchaseTotals.Total gte 0
</CF_ASSERT>

所需的输出将是一个html表,每一行都是查询中未通过断言的行。所以对我来说,CF_ASSERT标签需要能够更新当前行。

编辑2:

主要挑战是允许在标记正文中使用html,同时仍然从相应的行替换查询值:

<CF_ASSERT query="purchaseTotals">
  <CF_CONDITION expression="purchaseTotals.Total gte 0">
    <!---error message when expression is false--->
    <cfoutput>
      Purchase #purchaseTotals.purchaseId# has a negative total!
    </cfoutput>
  </CF_CONDITION>
  <CF_CONDITION expression="purchaseTotals.Total eq ''">
    #PurchaseTotals.purchaseId# has a null total, this may be caused by:
    <ul>
      <li>Edge Case 1</li>
      <li>Edge Case 2</li>
    </ul>
  </CF_CONDITION>
<CF_ASSERT>

这里的输出类似于:

  Purchase 120 has a negative total!
  Purchase 157 has a negative total!
  Purchase 157 has a null total, this may be caused by:
  • Edge Case 1
  • Edge Case 2

2 个答案:

答案 0 :(得分:2)

  

上述链接中描述的功能是否已从CF9中删除?

自2006年撰写文章以来,内部的东西已经发生了变化。但我怀疑你所描述的完全功能可能不存在于任何mx版本中。您的代码与关联示例之间的主要区别在于<cfoutput query="..">(不仅仅是普通<cfoutput>)的使用。在评估变量时,query属性显然提供了一些额外的上下文。删除它(如在您的示例中),结果是“第一行的值,而不是currentRow。”。即使在MX6下,这对后续版本来说也不是好兆头。确切的功能可能没有删除。它从来没有开始工作。

  

如果有,还有替代方案吗?

正如我之前所说,最干净的方法是使用数组概念,即#query.column[row]#。鉴于您似乎拒绝了该选项,您基本上只剩下evaluate()。您需要在父标记内循环查询。然后使用evaluate处理子标签表达式和内容。它不是特别优雅或简单的IMO。但我认为这可能是好的,因为它没有数组符号,或某种仪式牺牲。

<强> ASSERT.cfm

<cfparam name="attributes.query" type="string">

<cfif thisTag.ExecutionMode is 'start'> 
    <!--- validate attributes.query is a query object --->
    <cfif not ( structKeyExists(caller, attributes.query) AND IsQuery(caller[attributes.query]) )>
        <cfthrow message="Attributes.query [#attributes.query#] is undefined or not a query object">
    </cfif>
</cfif>
<cfif thisTag.ExecutionMode is 'end'> 
    <cfset variables[attributes.query] = caller[attributes.query]> 
    <cfloop query="variables.#attributes.query#">
        <cfloop array="#thisTag.assocAttribs#" index="subTag">
            <cfset variables.matchFound = evaluate(subTag.expression)>
            <cfif variables.matchFound>
                <cfoutput>[#currentRow#] #evaluate(DE(subTag.Content))#</cfoutput><hr>
            </cfif>
        </cfloop>
    </cfloop>
</cfif>

<强> CONDITION.cfm
注意: NOT 在标记内容中使用<cfoutput>标记。

<cfparam name="attributes.expression" type="string">
<cfif thisTag.ExecutionMode is "start"> 
    <cfassociate baseTag="CF_ASSERT">
</cfif>
<cfif thisTag.ExecutionMode is "end"> 
    <cfset attributes.content = thisTag.GeneratedContent>
    <cfset thisTag.GeneratedContent = "">
</cfif>
  

客户对CF的理解水平很低,但很漂亮   扎实编写SQL

说了这么多,是不是以这种方式实现的,因为它是最好的方法,或者因为它与编写SQL最相似,即舒适?

答案 1 :(得分:1)

内部平台效应的经典例子。

我建议你不要这样做,因为你正在尝试创建一个系统,该系统模仿基础或运行系统的内置功能,最终成为运行/实现的系统的一个执行不佳的版本。

听起来很混乱,我知道 - 但这是一个众所周知的反模式要避免。

有关详细信息,请参阅此处:http://en.wikipedia.org/wiki/Inner-platform_effect

P.S。你正在寻找什么(虽然我不同意实现)是在cfloop之外的查询的迭代,只需使用数组语法:

#queryName.fieldName[rowNumber]#

使用它你可以根据需要迭代查询,当然不需要底层的java。请注意,我们没有使用queryName.currentRow。对于previous()next()功能,您只需向上或向下更改rowNumber。