我正在构建一个对象来搜索我的数据库中的订单。用户可以设置许多可能的参数,并且可以设置每次搜索所需的数量。我已经创建了setter方法来收集搜索所需的所有参数。
我的问题是这个。什么是“最佳实践”
WHERE
方法时构建doSearch
子句WHERE
子句我想了解任何推荐背后的原因。
请注意,对象会针对每次搜索进行实例化,因此我不必担心使用不同参数进行第二次搜索。
答案 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>