Question

Je construis un objet pour rechercher des ordres dans ma base de données. L'utilisateur peut définir un grand nombre de paramètres possibles, et ils peuvent en définir autant que nécessaire pour chaque recherche. J'ai créé des méthodes de définition pour collecter tous les paramètres nécessaires à la recherche.

Ma question est la suivante. Quelle serait la "meilleure pratique"

  1. Stockage des paramètres et construction de la clause WHERE lorsque la méthode doSearch est appelée
  2. Construction de la clause WHERE lorsque les paramètres sont définis

J'aimerais comprendre la raison de toute recommandation.

Notez que l'objet est instancié pour chaque recherche. Je n'ai donc pas à me soucier d'une seconde recherche avec des paramètres différents.

Était-ce utile?

La solution

Vous devez séparer le code de votre recherche d’ordre du code qui construit le code SQL. Le code SQL doit être intégré dans un dérivé (ou dérivé de la stratégie ) du OrderSearch <. / code> classe. Une fois que vous avez effectué cette séparation, importe peu quand vous construisez le code SQL.

Pour rendre cela un peu plus simple. Dans le cas d'une classe nommée OrderSearch qui possède de nombreuses méthodes de définition pour les critères de recherche, vous souhaitez créer une sous-classe nommée OrderSearchSQLBuilder . Notez que la sous-classe dépend de la classe de base et que la classe de base est indépendante de la sous-classe. C'est très important. Cette indépendance vous permet de ne pas tenir compte du fait que le code SQL est construit dans les méthodes de définition ou dans la méthode de recherche. Voir Principe d'inversion de dépendance (DIP) .

Une fois que vous avez ce type de séparation, vous pouvez remplacer le dérivé par d'autres stratégies. Par exemple, si vous souhaitez tester votre application sans la connecter à la base de données SQL, vous pouvez créer une base de données fictive in-ram et créer un dérivé de OrderSearch qui traite de cette base factice. Le reste de l'application serait parfaitement ignorant et vos tests seraient alors indépendants des horreurs des connexions à la base de données, des données préexistantes, etc.

Autres conseils

Dans votre méthode, utilisez simplement les paramètres de votre SQL dynamique qui effectue la recherche. De cette façon, la clause where est construite juste avant l’exécution de SQL. Vous passerez simplement les paramètres de recherche dans votre méthode sous forme d'arguments.

Quelque chose comme ça ...

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

Ne construisez pas la clause where avant de pouvoir exécuter la recherche. Vous pouvez vous retrouver avec une interface utilisateur qui introduit des paramètres dans des itérations et vous ne savez pas quand vous avez tout. De plus, vous ne pouvez jamais exécuter la recherche, alors pourquoi vous soucier de la clause where.

Je ne pense pas que cela fasse une grande différence, mais j'estime qu'il semble préférable de construire la clause WHERE lorsque vous effectuez une recherche. Je ne pense pas que ce soit un paramètre qui doive être ajouté à une chaîne de clause WHERE par un installateur.

Sur une base de données SQLServer, il est plus efficace d’inclure tous les paramètres dans la clause where plutôt que de les construire à la volée. Ensuite, ayez un index de base de données qui inclut toutes les colonnes sur lesquelles vous allez chercher. Cela garantit que l'index est toujours utilisé lors de l'exécution de l'instruction.

Ne parlez pas comme si votre abstraction était tout à fait juste.

La recherche peut être meilleure comme méthode de "commandes". objet. transmettez les paramètres à la fonction de recherche et construisez la requête manuellement en tant que russ suggéré . Tout ce qui est spécifique aux commandes plutôt que la recherche peut alors être défini sur la méthode init des commandes.

Il est possible que vous souhaitiez créer un objet de recherche d'ordres, mais vous devez le faire via un objet d'ordres, pour que votre code frontal reste simple.

L'option 1 est votre meilleur choix. L'option 2 semble dangereuse. Et si un paramètre est mis à jour? Comment la remplacez-vous dans votre clause WHERE?

Je voudrais faire quelque chose comme ça:

<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>
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top