我是否必须在Coldfusion中查询输出范围?

时间:2012-05-22 19:54:01

标签: mysql coldfusion scope

如果我在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 个答案:

答案 0 :(得分:7)

有些人会告诉你,始终保持范围是一种很好的习惯做法,因为这样可以避免在极其重要的地方出现范围错误。

在个人观点中,我喜欢将cfoutput与查询一起使用的方法,而不是范围 - 它在其他语言中等同于“WITH”。由于查询将始终在查询驱动的cfoutput标记内的表单和url作用域之前进行评估,因此我没有看到在该实例中省略该作用域的任何问题。请记住,在CFC中,“参数”和本地范围都是抢占式的 - 但这不是查询驱动的cfoutput的最佳位置 - 它是为方便的显示设计(设计合理)

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

答案 1 :(得分:5)

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

你会得到一些人说你不会遇到足以证明额外输入的问题,而且它不是DRY,但是因为ColdFusion有一个scope evaluation order如果你有代码你想要工作,这是必需的背景。

通过下面的“查询循环”,我的意思是cfloopcfoutput,其中包含query个参数。

因此可以在查询循环中使用#columnname#

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

在所有情况下, #cfScope.queryName.columnName#

这是一个出错的例子。希望你永远不必处理这样的代码,但它可以指出ColdFusion的广泛scope evaluation的问题。

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

输出的结果是这不是来自查询;参数范围。the scope evaluation docs相反,以及其他人会相信的内容。

正如其他人所建议您可以将输出行更改为<cfoutput>#Query.xlocal#</cfoutput>,但这也无济于事。相反,你被告知该列不存在。将其更改为<cfoutput>#Query.xarguments#</cfoutput>将表明它使用的ArgumentsQuery代替localVariables

那怎么样:

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

这种方式比任何人都想要做的更多,但如果你想确保代码中没有任何讨厌的错误,则需要输入。

答案 2 :(得分: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>

答案 3 :(得分:2)

这是一个很好的讨论,讨论何时有必要以及什么时候对范围有价值。

如果只有清晰度进出CFC,我会向 始终 确定方向投掷我的两个便士。如果必须,var q ='';然后只引用q,这样你就有了一个本地范围的变量,如果你很懒,并且相信DRY包括范围。

我无法告诉你我所处理的系统和页面的数量是如此糟糕,以至于我不得不调试以找出来自哪里的内容。特别是在涉及分组和次要数据的复杂报告中;它会变得非常混乱。

我看到人们使用技巧(知情或不知情),他们默认一个没有作用范围的参数将被分配到“变量”范围,然后在他们的代码中,他们将混合表格和URL,期待一个覆盖另一个,和/或变量范围值没有作用域,以便输出总是找到值的默认变量版本....当然,该代码不像他们预期的那样......唉!

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

当然,在非常简单的输出情况下,我可能会在CFC外部放弃“变量”范围,但是在页面中没有混合其他范围的非常基本的输出,但我发现这很少见。

对我而言,总是养成正确确定价值观的习惯更为简单。

I.e。:

<cfprocresult name="Local.qExtern">

然后:

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

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

CLARITY&amp;维护

下一个程序员和六个月后查看一些代码的自己的清晰度比没有范围保存的几个键击更有价值。如果您的代码比在循环它时简单地转储查询更复杂并且其他逻辑或变量/值散布在您的输出中,则尤其如此。

BLEEDING&amp; LOCKING

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

<强> SPEED:

最后,我怀疑,在JS和其他语言中,即使在默认范围内,CF引擎也比未编码的变量更快地找到范围变量。

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