单个参数或构建Where子句

时间:2009-03-06 05:36:32

标签: mysql oop coldfusion

我正在构建一个对象来搜索我的数据库中的订单。用户可以设置许多可能的参数,并且可以设置每次搜索所需的数量。我已经创建了setter方法来收集搜索所需的所有参数。

我的问题是这个。什么是“最佳实践”

  1. 存储参数,并在调用WHERE方法时构建doSearch子句
  2. 在设置参数时构建WHERE子句
  3. 我想了解任何推荐背后的原因。

    请注意,对象会针对每次搜索进行实例化,因此我不必担心使用不同参数进行第二次搜索。

7 个答案:

答案 0 :(得分:13)

您应该将订单搜索的代码与构建SQL的代码分开。 SQL应该构建在OrderSearch类的派生(或Strategy衍生物)中。完成这种分离后,构建SQL时 并不重要。

使这更加简单明了。给定一个名为OrderSearch的类,它有一堆用于搜索条件的setter方法,您希望有一个名为OrderSearchSQLBuilder的子类。请注意,子类依赖于基类,并且基类独立于子类。这是非常重要的。这种独立性允许您忽略SQL是在setter方法中还是在搜索方法中构建的。请参阅The Dependency Inversion Principle (DIP)

一旦你有这种分离,你可以用其他策略替换衍生物。例如,如果要在不将其连接到SQL数据库的情况下测试应用程序,则可以创建虚拟内部数据库并创建处理该虚拟数据库的OrderSearch衍生物。应用程序的其余部分将无法意识到,您的测试将独立于数据库连接,预先存在的数据等的恐怖。

答案 1 :(得分:3)

在您的方法中,只需使用动态SQL中的参数进行搜索。这样,where子句就在SQL运行之前构建。您只需将搜索参数作为参数传递给方法。

像这样......

<cffunction name="getByAttributesQuery" access="public" output="false" returntype="query">
    <cfargument name="id" type="numeric" required="false" />
    <cfargument name="userName" type="string" required="false" />
    <cfargument name="firstName" type="string" required="false" />
    <cfargument name="lastName" type="string" required="false" />
    <cfargument name="createdAt" type="date" required="false" />
    <cfargument name="updatedAt" type="date" required="false" />
    <cfargument name="orderby" type="string" required="false" />

    <cfset var qList = "" />        
    <cfquery name="qList" datasource="#variables.dsn#">
        SELECT  
            id,
            userName,
            firstName,
            lastName,
            createdAt,
            updatedAt
        FROM    users
        WHERE       0=0
    <cfif structKeyExists(arguments,"id") and len(arguments.id)>
        AND id = <cfqueryparam value="#arguments.id#" CFSQLType="cf_sql_integer" />
    </cfif>
    <cfif structKeyExists(arguments,"userName") and len(arguments.userName)>
        AND userName = <cfqueryparam value="#arguments.userName#" CFSQLType="cf_sql_varchar" />
    </cfif>
    <cfif structKeyExists(arguments,"firstName") and len(arguments.firstName)>
        AND firstName = <cfqueryparam value="#arguments.firstName#" CFSQLType="cf_sql_varchar" />
    </cfif>
    <cfif structKeyExists(arguments,"lastName") and len(arguments.lastName)>
        AND lastName = <cfqueryparam value="#arguments.lastName#" CFSQLType="cf_sql_varchar" />
    </cfif>
    <cfif structKeyExists(arguments,"createdAt") and len(arguments.createdAt)>
        AND createdAt = <cfqueryparam value="#arguments.createdAt#" CFSQLType="cf_sql_timestamp" />
    </cfif>
    <cfif structKeyExists(arguments,"updatedAt") and len(arguments.updatedAt)>
        AND updatedAt = <cfqueryparam value="#arguments.updatedAt#" CFSQLType="cf_sql_timestamp" />
    </cfif>
    <cfif structKeyExists(arguments, "orderby") and len(arguments.orderBy)>
        ORDER BY #arguments.orderby#
    </cfif>
    </cfquery>

    <cfreturn qList />
</cffunction>

答案 2 :(得分:1)

在执行搜索之前,不要构建where子句。您最终可能会在迭代中提供参数的用户界面,并且您不知道何时拥有所有内容。此外,您可能永远不会执行搜索,所以为什么要担心where子句。

答案 3 :(得分:1)

我认为它没有多大区别,但我认为在doSearch时构建WHERE子句似乎更好。我不认为设置器的责任在于将参数添加到某处的WHERE子句字符串。

答案 4 :(得分:0)

在SQLServer数据库上,将所有参数包含在where子句中而不是动态构建它是更有效的。然后有一个数据库索引,其中包含您要搜索的所有列。这可确保在执行语句时始终使用索引。

答案 5 :(得分:0)

听起来你的抽象是不对的。

搜索可能更适合作为“订单”对象的方法。将参数传递给搜索功能并手动构建查询russ suggested。然后可以在订单init方法上设置任何特定于订单而不是搜索的内容。

您可能想要构建订单搜索对象,但这应该通过订单对象完成,以保持前端代码简单。

答案 6 :(得分:0)

选项1是您最好的选择。选项2听起来很危险。如果参数更新怎么办?如何在WHERE子句中替换它?

我会做这样的事情:

<cffunction name="doSearch" access="public" output="false" returntype="query">        
    <cfset var qList = "" />
    <cfquery name="qList" datasource="#variables.dsn#">
       SELECT
           ...
       FROM
           ...
       WHERE 0=0 
         <cfif len(getID())>
           AND id = <cfqueryparam value="#getID()#" CFSQLType="cf_sql_integer" />
         </cfif>       
         <cfif len(getUserName())>
           AND userName = <cfqueryparam value="#getUserName()#" CFSQLType="cf_sql_varchar" />
         </cfif>
    </cfquery>
    <cfreturn qList />
</cffunction>