是否将cfqueryparam与自定义标记一起使用?将本机标记与自定义标记嵌套



我基本上想允许这样的东西:

<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,它确实有效,但这显然是不可接受的。解析queryparam也是如此。

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

好吧,我刚刚发现我可以在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>
...

这个问题是可以解决的,但可能没有你希望的那么容易。

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

如果您想在工作中看到它的示例,请查看Neptune框架的Custom标签中的cf_DMQuery和cf_DMSQL标签。

https://github.com/sebtools/Neptune

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

总之,这是可以做到的,但预计会花一些时间

由于Mark Kruger(我尊敬和钦佩他)认为这样的标签只会增加开销,所以我要补充一点,这样的自定义标签可以带来真正的好处。我见过一些标签,其中包括在数据库连接断开导致故障的情况下重试整个查询调用(可能是对不同数据库的查询调用)的能力。

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

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

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

编辑:还有对integer的类型检查:IsValid("integer",somevalue);

同意,这并不比使用cfqueryparam更好,但根据用例的不同,它可能也不错。

相关内容

  • 没有找到相关文章

最新更新