2009-03-06 6 views
3

Ich baue ein Objekt, um Bestellungen in meiner Datenbank zu suchen. Es gibt eine Reihe möglicher Parameter, die der Benutzer festlegen kann, und sie können für jede Suche beliebig viele festlegen. Ich habe Setter-Methoden erstellt, um alle für die Suche benötigten Parameter zu sammeln.Individuelle Parameter oder Build Where-Klausel

Meine Frage ist dies. Was wäre „best practice“

  1. Speichern der Parameter sein, und den Aufbau der WHERE Klausel, wenn die doSearch Methode
  2. Aufbau der WHERE Klausel als Parameter festgelegt werden

genannt wird, würde Ich mag an den Grund für jede Empfehlung verstehen.

Beachten Sie, dass das Objekt für jede Suche instatiert wird, so dass ich mich nicht um eine zweite Suche mit anderen Parametern kümmern muss.

Antwort

13

Sie sollten den Code für Ihre Bestellung Suche aus dem Code trennen, die die SQL baut. Das SQL sollte in einem Derivat (oder Strategy Derivat) der Klasse OrderSearch eingebaut werden.Sobald Sie diese Trennung vorgenommen haben, ist es nicht wirklich wichtig wenn Sie die SQL erstellen.

Um dies ein wenig deutlicher zu machen. Mit einer Klasse namens OrderSearch, die eine Reihe von Setter-Methoden für die Suchkriterien enthält, möchten Sie eine Unterklasse namens OrderSearchSQLBuilder haben. Beachten Sie, dass die Unterklasse von der Basisklasse abhängt und dass die Basisklasse unabhängig von der Unterklasse ist. Dies ist sehr wichtig. Mit dieser Unabhängigkeit können Sie ignorieren, ob das SQL in den Setter-Methoden oder in der Suchmethode erstellt wurde. Siehe The Dependency Inversion Principle (DIP).

Sobald Sie diese Art von Trennung haben, können Sie das Derivat durch andere Strategien ersetzen. Wenn Sie z. B. Ihre Anwendung testen möchten, ohne sie mit der SQL-Datenbank zu verbinden, können Sie eine Pseudo-RAM-Datenbank erstellen und eine Ableitung von OrderSearch erstellen, die sich mit dieser Dummy-Datenbank befasst. Der Rest der Anwendung wäre glücklicherweise nicht bewusst, und Ihre Tests wären dann unabhängig von den Schrecken der Datenbankverbindungen, bereits vorhandenen Daten usw.

1

Erstellen Sie die WHERE-Klausel nicht, bevor sie zum Ausführen der Suche benötigt wird. Möglicherweise verfügen Sie über eine Benutzeroberfläche, die Parameter in Iterationen eingibt, und Sie wissen nicht, wann Sie alles haben. Außerdem können Sie die Suche nie ausführen. Warum sollten Sie sich also Gedanken über die where-Klausel machen?

0

In einer SQL Server-Datenbank ist es effizienter, alle Parameter in die where-Klausel aufzunehmen, anstatt sie im laufenden Betrieb zu erstellen. Dann haben Sie einen Datenbankindex, der alle Spalten enthält, nach denen Sie suchen werden. Dies stellt sicher, dass der Index immer verwendet wird, wenn die Anweisung ausgeführt wird.

3

Verwenden Sie in Ihrer Methode einfach die Parameter in Ihrem dynamischen SQL, die die Suche ausführen. Auf diese Weise wird die WHERE-Klausel unmittelbar vor dem Ausführen der SQL-Anweisung erstellt. Sie übergeben die Suchparameter einfach als Argumente an Ihre Methode.

So etwas ...

<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

Lassen Sie die len (...) checks - sie sollten nicht da sein. –

+0

Ich muss die Parameter für die Suche vor der eigentlichen Suche festlegen, so dass ich nicht einfach alle Parameter an die Methode doSearch übergeben kann. Ich denke auch, dass durch die Bereitstellung von Setter-Methoden außerhalb der DoSearch-Methode gibt mir eine flexiblere OrderSearch-Objekt – Yisroel

+0

>> Ich muss die Parameter für die Suche vor der eigentlichen Suche einstellen, so kann ich nicht einfach alle Parameter in die DoSearch übergeben Methode << Huh? Nicht einmal mit sowas wie doSearch (ArgumentCollection = Variables.SearchData)? –

1

Ich glaube es nicht viel Unterschied macht, aber ich denke, es ist besser Praxis scheint die WHERE-Klausel, wenn Sie doSearch zu bauen. Ich denke nicht, dass ein Setter dafür verantwortlich sein sollte, dass ein Parameter irgendwo in eine WHERE-Klausel eingefügt wird.

0

Es klingt nicht ganz so, als ob Ihre Abstraktion ganz richtig ist.

Suche kann besser als eine Methode eines "Bestellungen" -Objekts sein. Übergeben Sie die Parameter an die Suchfunktion und erstellen Sie die Abfrage manuell als russ suggested. Alles, was für Bestellungen und nicht für die Suche spezifisch ist, kann dann in der Order-Init-Methode eingestellt werden.

Es ist möglich, dass Sie vielleicht ein Orders-Suchobjekt erstellen möchten, aber dies sollte über ein Orders-Objekt erfolgen, um Ihren Front-End-Code einfach zu halten.

+0

Welche Funktionalität bietet das Orders-Objekt? – Yisroel

0

Option 1 ist Ihre beste Wahl. Option 2 klingt gefährlich. Was passiert, wenn ein Parameter aktualisiert wird? Wie ersetzen Sie es in Ihrer WHERE-Klausel?

Ich würde so etwas tun:

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

Ich muss mich nicht um die Aktualisierung eines Parameters kümmern, da für jede Suche eine neue OrderSearch eingerichtet wird. Im Wesentlichen mache ich genau so, wie Sie oben tun. Ich wollte nur klar verstehen, was mit der anderen Option nicht stimmt. BTW, Sie rufen getUserName(), aber dann reference arguments.userName – Yisroel