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

发布于 2024-11-18 18:46:40 字数 2286 浏览 2 评论 0原文

我正在尝试编写一个自定义标签,它将以特殊方式迭代 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>

Produces:

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

I am trying to write a custom tag that will iterate over a cfquery object in a special way. I found this page: http://www.zrinity.com/developers/mx/undocumentation/query.cfm outlining how to use the underlying java methods to navigate the result set, but it doesn't seem to be working in CF9.

I can call .next(), .previous(), .first(), and .last() just fine, and each method updates query.currentRow, but referencing query.columnName always returns the value from the first row, not currentRow.

Example:

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

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

Produces:

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

I know i could use something like testQuery.fooName[testQuery.currentRow], but that is pretty undesirable for the people I am making the custom tag for. Was the functionality described in the above link removed from CF9? If so is there an alternative?

EDIT

To expand on the why, the client wants a custom tag that allows them to "assert" certain things about a query. The client has a pretty low level understanding of CF, but are pretty solid writing SQL. Their desired end result is something akin to:

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

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

The desired output would be a html table with each row being the row from the query that fails the assertion. So to me, the CF_ASSERT tag need to be able to update the current row.

Edit 2:

The main challenge is to allow html in the body of the tag, while still having query values substituted from the appropriate row:

<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>

The output here would be something like:

  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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

剑心龙吟 2024-11-25 18:46:40

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

自 2006 年撰写本文以来,内部内容确实发生了变化。但我怀疑您所描述的确切功能可能在任何 mx 版本中都不存在。您的代码与链接示例之间的主要区别在于 的使用(而不仅仅是普通的 )。 query 属性显然在评估变量时提供了一些额外的上下文。删除它(就像在您的示例中一样),结果是“第一行的值,而不是 currentRow。”。即使在 MX6 下,这对于后续版本来说也不是好兆头。这个确切的功能可能没有被删除。它从一开始就没起作用。

如果是的话还有其他选择吗?

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

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
注意:不要在标签内容中使用标签。

<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 最相似,即舒适?

Was the functionality described in the above link removed from CF9?

The internal stuff has definitely changed since the article was written in 2006. But I suspect the exact functionality you are describing may not have existed in any mx version. A key difference between your code and the linked examples is the usage of <cfoutput query=".."> (not just a plain <cfoutput>). The query attribute obviously provides some extra context when evaluating the variables. Remove it (like in your example) and the results are "the value from the first row, not currentRow.". Even under MX6, which does not bode well for subsequent versions. That exact functionality probably was not removed. It just never worked to begin with.

If so is there an alternative?

Like I said earlier, the cleanest approach would be to use array notion ie #query.column[row]#. Given that you seem to have rejected that option, you are basically left with evaluate(). You would need to loop through the query within the parent tag. Then use evaluate to process the subtag expression and content. It is not particularly elegant or simple IMO. But I think that may be good as it gets without array notation, or a ritual sacrifice of some kind.

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
Note: Do NOT use <cfoutput> tags within the tag content.

<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>

client has a pretty low level understanding of CF, but are pretty
solid writing SQL

Having said all that, are things being implemented this way because it is the best approach or because it is most similar to writing SQL ie comfortable ?

情深如许 2024-11-25 18:46:40

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

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

听起来令人困惑,我知道——但这是众所周知的要避免的反模式。

请参阅此处了解更多信息:http://en.wikipedia.org/wiki/Inner-platform_effect

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

#queryName.fieldName[rowNumber]#

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

Classic example of the inner platform effect.

I would advise you not to do this as you are trying to create a system which mimics built in functionality of the base or running system which ultimately becomes a poorly implemented version of the system in which it is running on / implemented in.

Sounds confusing, I know - but this is a well known anti-pattern to avoid.

See here for more information : http://en.wikipedia.org/wiki/Inner-platform_effect

P.s. what you are looking for (although I disagree with the implementation) is itteration of a query outside of a cfloop, simply use array syntax :

#queryName.fieldName[rowNumber]#

Using this you can itterate the query however you wish, certainly no need for underlying java. Notice we aren't using queryName.currentRow. For previous() next() functionality, you just change the rowNumber up or down.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文