3

如果我在 Coldfusion 中运行数据库查询/存储过程,那么引用从查询返回的字段的正确方法是什么?

<cfstoredproc procedure="proc_select_extern" datasource="stokkers">
    <cfprocparam type="in" value="#Session.Extern#" cfsqltype="cf_sql_varchar" maxlength="13">
    <cfprocresult name="extern">
</cfstoredproc>
<cfoutput query="extern">
   <cfset variables.some = extern.foo>
   OR 
   <cfset variables.some = foo>
</cfouput>

假设extern包括 foo、bar 和 foobar。是否允许并且更好地编写:

 extern.foo;
 extern.bar;
 extern.foobar;

因为我正在浏览一个页面,并且经常发现这些“裸”变量有点令人困惑:

 foo;
 bar;
 foobar;

有很多关于范围和正确范围的信息,但我在查询输出中没有找到任何信息。

感谢您的澄清!

4

4 回答 4

7

有些人会告诉您,始终确定范围是一种很好的习惯做法,因为它可以防止您在真正重要的地方犯下范围错误。

就我个人而言,我喜欢将 cfoutput 与查询一起使用而不必限定范围的方法——它相当于其他语言中的“WITH”。由于查询将始终在查询驱动的 cfoutput 标记内的表单和 url 范围之前进行评估,因此在该实例中离开范围没有任何问题。请记住,在 CFC 中,“参数”和本地范围都是抢占式的——但这不是查询驱动的 cfoutput 的最佳位置——它是为方便显示而设计(巧妙设计)的。

但同样......其他人会告诉你不同的(也有一些激情:)。

于 2012-05-22T20:03:06.467 回答
5

如果您没有完全确定变量的范围,则存在范围问题。

你会得到人们说你不会遇到足以证明额外输入的问题,而且它不是 DRY,但是因为 ColdFusion 有一个范围评估顺序,如果你有想要在任何上下文中工作的代码,它是必需的。

下面的“查询循环”是指一个cfloopcfoutput带有一个query参数。

所以你可以#columnname#在查询循环中使用。

可以 #queryName.columnName#在查询循环内部或外部。

应该 #cfScope.queryName.columnName#在所有情况下。

这是一个出错的例子。希望您永远不必处理这样的代码,但这有助于指出 ColdFusion 广泛的范围评估存在的问题。

<cfset testcfc = new Test().scopeTest()>

<cfcomponent output="false">

    <cffunction name="scopeTest" access="public" output="true" returntype="void">
        <cfargument name="Query" type="query" required="false" default="#QueryNew("xarguments")#">
        <cfargument name="xlocal" type="string" required="false" default="This is not from a query; Arguments scope.">

        <cfset QueryAddRow(Arguments.Query, 1)>
        <cfset Arguments.Query["xarguments"][1] = "this is the arguments scope query">
        <cfset local.Query = QueryNew("xlocal")>
        <cfset QueryAddRow(local.Query, 1)>
        <cfset local.Query["xlocal"][1] = "this is the local scope query">
        <cfset Variables.Query = QueryNew("xVariables")>
        <cfset QueryAddRow(Variables.Query, 1)>
        <cfset Variables.Query["xVariables"][1] = "this is the variables scope query">

        <cfset local.xlocal = "This is not from a query; local scope.">

        <cfloop query="Query">
            <cfoutput>#xlocal#</cfoutput>
        </cfloop>

        <cfdump var="#Arguments#" label="Arguments">
        <cfdump var="#local#" label="local">
        <cfdump var="#variables#" label="Variables">
        <cfabort>
    </cffunction>

</cfcomponent>

输出的结果是这不是来自查询;参数范围。范围评估文档的内容以及其他人希望您相信的内容相反。

正如其他人所建议的那样,您可以将输出行更改为读取<cfoutput>#Query.xlocal#</cfoutput>,但这也无济于事。相反,您会被告知该列不存在。将其更改为<cfoutput>#Query.xarguments#</cfoutput>将表明它使用的是Arguments版本Query而不是localor Variables

那么怎么样:

        <cfloop query="local.Query">
            <cfoutput>#xlocal#</cfoutput>
        </cfloop>

没有。仍然不是想要的结果。好的,那么如何将查询名称添加到输出中:

        <cfloop query="local.Query">
            <cfoutput>#Query.xlocal#</cfoutput>
        </cfloop>

没有。仍然不是想要的结果。如果您想确保获得正确的结果,您必须全面了解所有内容。

        <cfloop query="local.Query">
            <cfoutput>#local.Query.xlocal#</cfoutput>
        </cfloop>

这比任何人都想做的要多得多,但如果你想确保代码中没有任何令人讨厌的错误,这是必需的。

于 2012-05-23T10:25:20.857 回答
3

我是那些会告诉你你应该把所有东西都放在范围内的人之一。在阅读您自己的代码和其他代码时,它确实很有帮助。我说“毫无疑问,把它找出来!”

下面是我通常如何进行查询然后输出结果的示例。

<cfscript>
Q = MyCFC.getCustomers();
if (! isQuery(Q) || Q.RecordCount == 0) {
    writeOutput("No records found.");
}  else {
    for (i = 1; i lte Q.RecordCount; i++) {
        VARIABLES.Customer = "#Q.FirstName[i]# #Q.LastName[i]#";
        writeOutput(VARIABLES.Customer);
        writeOutput("<br>");
    }
}
</cfscript>
于 2012-05-22T20:10:01.567 回答
2

这是一个关于何时有必要以及何时对范围有价值的很好的讨论。

如果只是为了清晰地进出 CFC,我会将我的两便士投入到始终确定范围的方向上。如果必须, var q = ''; 然后只引用 q 如果你很懒并且相信 DRY 包含作用域,那么你就有一个局部作用域变量。

我无法告诉你我处理过的系统和页面的数量是如此之差,以至于我不得不调试以找出来自哪里的东西。特别是在涉及分组依据和辅助数据的复杂报告中;它会变得非常混乱。

一个令人烦恼的地方是我看到人们使用技巧(有意或无意),他们默认一个没有作用域的参数,将分配给“变量”范围,然后在他们的代码中,他们将混合表单和 URL,期望一个覆盖另一个和/或没有范围的变量范围值,因此输出总是会找到该值的默认变量版本......当然,该代码的行为不像他们预期的那样......哎呀!

即使在带有查询属性的 cfquery/cfoutput/cfloop 中,我也建议明确范围。此外,没有理由不能在 cfc/对象中使用 cfouput/cfloop。

当然,对于非常简单的输出,有时我可能会在 CFC 之外删除“变量”范围,以获得页面中没有混合其他范围的非常基本的输出,但我发现这种情况很少见。

对我来说,始终养成正确界定价值观的习惯会更简单。

IE:

<cfprocresult name="Local.qExtern">

接着:

<cfoutput query='Local.qExtern'> 
    #Local.qExtern.szNameFirst# 
    #Local.qExtern.szNameLast# 
</cfoutput>

总而言之,除了最简单的情况外,我提出了始终倾向于范围界定的 3 个原因:

清晰度和维护

对于下一个程序员和六个月后的你自己来说,看一点代码的清晰度比你通过不限定范围节省的几次击键更有价值。如果您的代码比在循环查询时简单地转储查询更复杂,并且其他逻辑或变量/值散布在您的输出中,则尤其如此。

出血和锁定

此外,当在 CFC 中并使用范围不正确的 var 时,您肯定会冒变量出血的风险,尤其是在默认范围进入受保护范围而不是本地范围的情况下。当多个方法*和/或单例方法访问一个公共(受保护的)范围并且需要将该变量从也尝试使用该名称空间的等待方法/请求中锁定时,我还看到了严重的性能下降(哦,是的,并且流血的)。

速度:

最后,我怀疑,就像在 JS 和其他语言中一样,CF 引擎比无范围变量更快地找到范围变量,即使在默认范围内也是如此。

*脚注:我想澄清发生这种情况的情况。范围不佳的单例(例如,缓存到应用程序的实用程序类)最有可能导致意外的受保护范围变量锁定,这可能会减慢您的系统/请求队列。在同一个请求中使用同一个变量的多个方法是这样的情况:一个非可变变量被视为一个局部范围的变量(递归函数,在同一个对象中调用其他辅助方法的方法)并且通常会导致出血(意外重用/操作相同的变量导致意外结果)。

于 2013-03-05T04:09:33.687 回答