Отдельные параметры или пункт Build Where - PullRequest
3 голосов
/ 06 марта 2009

Я строю объект для поиска заказов в моей базе данных. Есть множество возможных параметров, которые пользователь может установить, и они могут установить столько, сколько нужно для каждого поиска. Я создал методы установки для сбора всех параметров, необходимых для поиска.

Мой вопрос такой. Что было бы "лучшей практикой"

  1. Сохранение параметров и построение предложения WHERE при вызове метода doSearch
  2. Построение предложения WHERE при заданных параметрах

Я бы хотел понять причину любой рекомендации.

Обратите внимание, что объект устанавливается для каждого поиска, поэтому мне не нужно беспокоиться о втором поиске с другими параметрами.

Ответы [ 7 ]

13 голосов
/ 07 марта 2009

Вы должны отделить код для поиска вашего заказа от кода, который строит SQL. SQL должен быть встроен в производную (или Strategy производная) класса OrderSearch. После того как вы сделали это разделение, на самом деле не имеет значения , когда вы создаете SQL.

Чтобы сделать это немного проще. Если у вас есть класс с именем OrderSearch, в котором есть набор методов для критериев поиска, вы хотите иметь подкласс с именем OrderSearchSQLBuilder. Обратите внимание, что подкласс зависит от базового класса, и что базовый класс не зависит от подкласса. Это очень важно. Эта независимость позволяет не учитывать, встроен ли SQL в методы установки или в метод поиска. См. Принцип обращения зависимостей (DIP) .

Если у вас есть такой вид разделения, вы можете заменить производную другими стратегиями. Например, если вы хотите протестировать свое приложение, не подключая его к базе данных SQL, вы можете создать фиктивную оперативную базу данных и создать производную от OrderSearch, которая работает с этой фиктивной базой данных. Остальная часть приложения будет в блаженном неведении, и тогда ваши тесты будут независимы от ужасов соединений с базой данных, ранее существующих данных и т. Д.

3 голосов
/ 06 марта 2009

В вашем методе просто используйте параметры в вашем динамическом 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>
1 голос
/ 06 марта 2009

Я не думаю, что это имеет большое значение, но я думаю, что лучше будет строить предложение WHERE при выполнении поиска. Я не думаю, что сеттер должен отвечать за параметр, добавляемый в строку предложения WHERE где-либо.

1 голос
/ 06 марта 2009

Не создавайте предложение where, пока оно не понадобится для выполнения поиска. Вы можете получить пользовательский интерфейс, который передает параметры в итерациях, и вы не знаете, когда у вас все есть. Кроме того, вы никогда не сможете выполнить поиск, так что зачем беспокоиться о предложении where.

0 голосов
/ 07 марта 2009

Вариант 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>
0 голосов
/ 06 марта 2009

Не совсем похоже, что ваша абстракция совершенно правильная.

Поиск может быть лучше в качестве метода объекта «заказы». передайте параметры в функцию поиска и создайте запрос вручную, как предложено Русс . Все, что относится к заказам, а не к поиску, может быть установлено в методе init заказов.

Возможно, вы захотите построить объект поиска заказов, но это должно быть сделано через объект заказов, чтобы сохранить ваш код переднего плана простым.

0 голосов
/ 06 марта 2009

В базе данных SQLServer более эффективно включать все параметры в предложение where, а не создавать его на лету. Затем имейте индекс базы данных, который включает все столбцы, по которым вы будете искать. Это гарантирует, что индекс всегда используется при выполнении оператора.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...