2009-03-06 34 views
3

我在構建一個對象來搜索我的數據庫中的訂單。用戶可以設置一系列可能的參數,並且可以設置多達每個搜索所需的參數。我創建了setter方法來收集搜索所需的所有參數。個別參數或建立條款

我的問題是這樣的。什麼是「最佳實踐」

  1. 存儲的參數,並建立在doSearch方法被調用
  2. 構建WHERE子句參數設置

我想給WHERE條款瞭解任何建議背後的原因。

請注意,該對象是爲每個搜索instatiated,所以我不必擔心用不同的參數第二次搜索。

回答

13

您應該從構建SQL代碼訂單搜索分開的代碼。 SQL應該建立在OrderSearch類的衍生產品(或Strategy衍生產品)中。一旦你做了這個分離,當你建立SQL時並不重要。

爲了使這更簡單一點。給定一個名爲OrderSearch的類,它有一組搜索條件的setter方法,您希望有一個名爲OrderSearchSQLBuilder的子類。請注意,子類依賴於基類,並且基類獨立於子類。這個非常重要。這種獨立性允許您忽略SQL是在setter方法中還是在搜索方法中構建的。請參閱The Dependency Inversion Principle (DIP)

一旦你有這種分離,你可以用其他策略取代衍生物。例如,如果您想測試應用程序而不將其連接到SQL數據庫,則可以創建一個虛擬內存數據庫並創建處理該虛擬數據庫的衍生品OrderSearch。應用程序的其餘部分將會很幸福地不知道,然後您的測試將獨立於數據庫連接,預先存在的數據等的恐怖。

1

在需要執行搜索之前,不要構建where子句。您最終可能會得到一個用戶界面,它可以在迭代中提供參數,而且您不知道什麼時候擁有了所有內容。此外,你可能永遠不會執行搜索,所以爲什麼要擔心where子句。

0

在SQLServer數據庫上,將所有參數包含在where子句中而不是實時構建它會更高效。然後有一個數據庫索引,其中包括您將搜索的所有列。這可確保在執行語句時始終使用索引。

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> 
+0

放下len(...)檢查 - 它們不應該在那裏。 – 2009-03-06 10:12:27

+0

我需要在進行實際搜索之前設置搜索參數,所以我無法將所有參數都傳遞給doSearch方法。我也認爲通過在doSearch方法之外提供setter方法給了我一個更靈活的orderSearch對象 – Yisroel 2009-03-06 19:11:05

+0

>>我需要在進行實際搜索之前設置搜索參數,所以我不能簡單地將所有參數傳遞給doSearch方法<< 咦? 甚至沒有像doSearch(ArgumentCollection = Variables.SearchData)的東西? – 2009-03-07 00:41:29

1

我不認爲它使太大的區別,但我認爲它似乎更好的做法,當你doSearch構建WHERE子句。我不認爲它應該是setter的職責,以便在某處添加一個WHERE子句字符串的參數。

0

聽起來不像你的抽象是對的。

作爲「訂單」對象的一種方法,搜索可能會更好。將參數傳遞給搜索功能並手動構建查詢,如russ suggested。然後可以在訂單init方法上設置任何特定於訂單而不是搜索的內容。

您可能希望構建訂單搜索對象,但這應該通過訂單對象來完成,以保持您的前端代碼的簡單性。

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>