【问题标题】:Using cfqueryparam with custom tag? Nesting native tags with custom tags使用带有自定义标签的 cfqueryparam?使用自定义标签嵌套原生标签
【发布时间】:2014-12-26 14:45:07
【问题描述】:

我基本上想允许这样的事情:

<cf_datatables datasource="#someDS#">

    <cf_datatables_records>

        SELECT
            `someColumn1`,
            `someColumn2`

        FROM
            `#someDB#`.`#someT#`

        WHERE
            `someColumn1` = <cfqueryparam value="#someValue#"  cfSqlType="CF_SQL_INTEGER">

        LIMIT
            10

    </cf_datatables_records>

</cf_datatables>

cf_datatables_records 自定义标签(子)是一个子查询/记录集,将在cf_datatables 自定义标签(父)中使用。这将是执行上述操作时的 SQL 结果:

SELECT
    SQL_CALC_FOUND_ROWS *

FROM (

        SELECT
            `someColumn1`,
            `someColumn2`

        FROM
            `#someDB#`.`#someT#`

        WHERE
            `someColumn1` = <cfqueryparam value="#someValue#"  cfSqlType="CF_SQL_INTEGER">

        LIMIT
            10

) AS `base`

UNION (...)

WHERE ... GROUP BY ... ORDER BY ... LIMIT ... etc. (depends on the provided parameters)

不幸的是,ColdFusion 在将 cfqueryparam 标签传递给自定义标签之前先对其进行解析,导致:

Context validation error for tag cfqueryparam. The tag must be nested inside a cfquery tag.

如果我省略cfqueryparam,它确实有效,但这显然是不可接受的。解析查询参数也是如此。

知道如何解决这个问题吗?

【问题讨论】:

  • 不确定为什么会存在这些自定义标签。这就像对 cfquery 的重写,效果很好。我认为您无法解决此问题,除非您重写数据表自定义标记以在最终将其放入 cfquery 标记的位置包含 cfqueryparam。除了额外的解析开销之外,您不会从使用此自定义标记中获得任何好处。
  • AFAIK,这对于标签是不可能的。可能与 cfquery 的 cfscript 版本一起使用。但是,我也不确定我是否看到了这个的价值。用例是什么?旁注,根据#foo2##foo3# 的来源,您仍然可能将数据库暴露给sql 注入。
  • 目的是简化必须准备数据的方式。我希望我们的初级开发人员只关心记录,而不是动态过滤、确定可能的记录计数等附加信息所需的子选择。
  • 我发布的代码是通用的,只是描述了我想做的事情,也就是一个例子,所以实际的事情不仅仅是构建两个查询。一种可能的解决方案是通过参数传递查询,但这需要了解子选择,除非我愿意触发两倍的查询,即查询时查询。
  • 更好的方法可能是编写可供初级开发人员使用的存储过程。这将满足只处理记录的要求。

标签: coldfusion nested cfquery custom-tags cfqueryparam


【解决方案1】:

好的,我刚刚发现我可以在 cfquery 中包含 SQL 指令,而无需处理原生标记问题。

<cfquery datasource="#someDS#">

    <!--- count possible records --->
    <cfmodule dtArguments="#dtController.params#" template="datatables-processing-pre.cfm">

        <!--- select records for the desired entity --->
        SELECT
            `someColumn1`,
            `someColumn2`

        FROM
            `#someDB#`.`#someT#`

        WHERE
            `someColumn1` = <cfqueryparam value="#someValue#"  cfSqlType="CF_SQL_INTEGER">

        LIMIT
            10

    <!--- filter, order and paginate records --->
    <cfmodule dtArguments="#dtController.params#" template="datatables-processing-post.cfm">

</cfquery>

这两个包括动态补充选择。

datatables-processing-pre.cfm的内容:

SELECT
    SQL_CALC_FOUND_ROWS *

FROM (

datatables-processing-post.cfm的内容:

) AS 'base'

WHERE
    <cfswitch ...>
        <defaultcase>
            `someColumn3` > <cfqueryparam value="#someOtherValue#"  cfSqlType="CF_SQL_INTEGER">
        </defaultcase>
    </cfswitch>

    <cfif ...>
        AND `someColumn4` LIKE <cfqueryparam value="#anotherValue#%"  cfSqlType="CF_SQL_VARCHAR">
    </cfif>

ORDER BY
    <cfswitch ...>
        ...
    </cfswitch>

...

【讨论】:

    【解决方案2】:

    问题是可以解决的,但可能不像您希望的那么容易。

    您必须创建一个标签(或类似的标签)来替换您的标签。其中每一个都必须输出一个字符串,您可以使用该字符串(可能结合标签使其父标签可用的一些数据)稍后在父标签的 End 模式下通过一些循环和字符串替换来重新创建 cfqueryparam 标签。

    如果您想查看它的工作示例,请查看我的 Neptune 框架的自定义标记中的 cf_DMQuery 和 cf_DMSQL 标记。

    https://github.com/sebtools/Neptune

    您可以在存储库的“CustomTags”文件夹中找到它们。问题的症结在 DMUdfs.cfm 中的 convertSQLArray 函数中得到解决。它利用 DataMgr.cfc 中的功能来处理高度动态的 SQL 代码。

    总而言之,这是可以做到的,但需要花一些时间。

    自从 Mark Kruger(我尊重和钦佩他)提出这样的想法,即此类标签只会为您带来开销,我将补充说,此类自定义标签可以带来真正的好处。我看到的标签包括在由于数据库连接断开而失败的情况下重试整个查询调用(可能是对不同的数据库)的能力。

    我使用了它们,以便在多个不同的查询中使用复杂的 SQL(包括 cfqueryparams)。我获得了在 SQL 中执行复杂逻辑的速度优势,而无需重复代码。但是,很难发布这样的示例,因为您的情况必须达到一定程度的复杂性才能得到回报(这使得很难想出一个简洁的示例)。

    【讨论】:

    • 感谢您的建议和活生生的例子,但这种解决方法 - 正如您已经指出的那样 - 并不是我想要的。发现 CF 的 cfinclude/cfmodule 的工作方式与我试图让自定义标签的行为方式一样,我会坚持下去。马克克鲁格:没有冒犯的意思,但他基本上是在建议忽略 DRY 原则。我不会因为不能在自定义标签中使用原生子标签而在 20 个不同的文件中重复相同的 sql 语句和条件构建。
    【解决方案3】:

    为什么不在执行查询之前添加一个检查以查看值是否是正确的类型,而不是 cfqueryparam?

    <cfif NOT IsNumeric(somevalue)>
      <cfabort>
    </cfif>
    

    编辑:也有整数类型检查:IsValid("integer", somevalue);

    同意,这并不比使用 cfqueryparam 更好,但根据用例可能没问题。

    【讨论】:

    • 这至少在两个层面上是错误的: 1. ColdFusion 的 isNumeric 接受任何会导致 SQL 在整数字段上失败的数值(例如十进制)。 2. 处理 SQL 字符串不仅仅是简单的正则表达式检查。转义还取决于使用的 SQL 供应商。
    猜你喜欢
    • 2012-07-13
    • 1970-01-01
    • 1970-01-01
    • 2017-02-10
    • 1970-01-01
    • 2018-01-03
    • 2013-10-14
    • 2013-01-11
    • 2017-07-03
    相关资源
    最近更新 更多