我在構建一個對象來搜索我的數據庫中的訂單。用戶可以設置一系列可能的參數,並且可以設置多達每個搜索所需的參數。我創建了setter方法來收集搜索所需的所有參數。個別參數或建立條款
我的問題是這樣的。什麼是「最佳實踐」
- 存儲的參數,並建立在
doSearch
方法被調用 - 構建
WHERE
子句參數設置
我想給WHERE
條款瞭解任何建議背後的原因。
請注意,該對象是爲每個搜索instatiated,所以我不必擔心用不同的參數第二次搜索。
我在構建一個對象來搜索我的數據庫中的訂單。用戶可以設置一系列可能的參數,並且可以設置多達每個搜索所需的參數。我創建了setter方法來收集搜索所需的所有參數。個別參數或建立條款
我的問題是這樣的。什麼是「最佳實踐」
doSearch
方法被調用WHERE
子句參數設置我想給WHERE
條款瞭解任何建議背後的原因。
請注意,該對象是爲每個搜索instatiated,所以我不必擔心用不同的參數第二次搜索。
您應該從構建SQL代碼訂單搜索分開的代碼。 SQL應該建立在OrderSearch
類的衍生產品(或Strategy衍生產品)中。一旦你做了這個分離,當你建立SQL時並不重要。
爲了使這更簡單一點。給定一個名爲OrderSearch
的類,它有一組搜索條件的setter方法,您希望有一個名爲OrderSearchSQLBuilder
的子類。請注意,子類依賴於基類,並且基類獨立於子類。這個非常重要。這種獨立性允許您忽略SQL是在setter方法中還是在搜索方法中構建的。請參閱The Dependency Inversion Principle (DIP)。
一旦你有這種分離,你可以用其他策略取代衍生物。例如,如果您想測試應用程序而不將其連接到SQL數據庫,則可以創建一個虛擬內存數據庫並創建處理該虛擬數據庫的衍生品OrderSearch
。應用程序的其餘部分將會很幸福地不知道,然後您的測試將獨立於數據庫連接,預先存在的數據等的恐怖。
在需要執行搜索之前,不要構建where子句。您最終可能會得到一個用戶界面,它可以在迭代中提供參數,而且您不知道什麼時候擁有了所有內容。此外,你可能永遠不會執行搜索,所以爲什麼要擔心where子句。
在SQLServer數據庫上,將所有參數包含在where子句中而不是實時構建它會更高效。然後有一個數據庫索引,其中包括您將搜索的所有列。這可確保在執行語句時始終使用索引。
在您的方法中,只需使用執行搜索的動態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>
我不認爲它使太大的區別,但我認爲它似乎更好的做法,當你doSearch構建WHERE子句。我不認爲它應該是setter的職責,以便在某處添加一個WHERE子句字符串的參數。
聽起來不像你的抽象是對的。
作爲「訂單」對象的一種方法,搜索可能會更好。將參數傳遞給搜索功能並手動構建查詢,如russ suggested。然後可以在訂單init方法上設置任何特定於訂單而不是搜索的內容。
您可能希望構建訂單搜索對象,但這應該通過訂單對象來完成,以保持您的前端代碼的簡單性。
選項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>
放下len(...)檢查 - 它們不應該在那裏。 – 2009-03-06 10:12:27
我需要在進行實際搜索之前設置搜索參數,所以我無法將所有參數都傳遞給doSearch方法。我也認爲通過在doSearch方法之外提供setter方法給了我一個更靈活的orderSearch對象 – Yisroel 2009-03-06 19:11:05
>>我需要在進行實際搜索之前設置搜索參數,所以我不能簡單地將所有參數傳遞給doSearch方法<< 咦? 甚至沒有像doSearch(ArgumentCollection = Variables.SearchData)的東西? – 2009-03-07 00:41:29