Cfqueryparam'd Запрос генерации из функции
Есть поисковый запрос и функция, которую я использую для генерации элементов запроса.
<cffunction name="GetSearchQuery" output="true" returntype="string" access="public">
<cfargument name="arrayName" type="array" required="yes">
<cfargument name="columnName" type="string" required="yes">
<cfargument name="searchtype" type="string" required="no" default="wildcard">
<cfset var o = "">
<cfset var i = "">
<cfset var search_item = "">
<cfset search_item = "(">
<cfloop from="1" to="#ArrayLen(Arguments.arrayName)#" index="o">
<cfif Arguments.arrayName[o][1] EQ #Arguments.columnName#>
<cfloop from="2" to="#ArrayLen(Arguments.arrayName[o])#" index="i">
<cfset search_item = search_item & #Arguments.columnName#>
<cfswitch expression="#Arguments.searchtype#">
<cfcase value="wildcard">
<cfset search_item = search_item & ' LIKE
<cfqueryparam value="%' & #Arguments.arrayName[o][i]# & '%"> AND '>
</cfcase>
<cfcase value="startswith">
<cfset search_item = search_item & ' LIKE
<cfqueryparam value="' & #Arguments.arrayName[o][i]# & '%"> AND '>
</cfcase>
<cfcase value="endswith">
<cfset search_item = search_item & ' LIKE
<cfqueryparam value="%' & #Arguments.arrayName[o][i]# & '"> AND '>
</cfcase>
<cfcase value="exactmatch">
<cfset search_item = search_item & ' =
<cfqueryparam value="' & #Arguments.arrayName[o][i]# & '"> AND '>
</cfcase>
</cfswitch>
</cfloop>
</cfif>
</cfloop>
<cfif Len(search_item) GT 4>
<cfset search_item = Left(search_item, Len(search_item)-4) & ") ">
</cfif>
<cfreturn search_item>
</cffunction>
И затем назовите это так в запросе
SELECT * FROM #request.tablename# WHERE #utilObj.GetSearchQuery(arrsearch, "photonumber", true)# ИЛИ #utilObj.GetSearchQuery(arrsearch, "takeby", true)# ИЛИ #utilObj.GetSearchQuery(arrsearch, "category", true)# OR #utilObj.GetSearchQuery(arrsearch, "area", true)# OR #utilObj.GetSearchQuery(arrsearch, "description", true)#
Но это вызывает ошибку в запросе
Но без cfqueryparam в функции это прекрасно работает.
например. <cfset search_item = search_item & ' LIKE "%' & #Arguments.arrayName[o][i]# & '%" AND '>
Есть ли в любом случае мы можем динамически добавлять cfqueryparam к запросу?
2 ответа
Вы не можете создать строку, содержащую CFML, и вывести ее и ожидать, что это как-то будет означать, что она действительно будет выполнена.
Во-первых, это немного глупо, когда вы останавливаетесь и думаете об этом, не так ли? (извините, я не имею в виду это подлым образом). И не чувствую себя плохо: я думаю, что мы все сделали это на каком-то этапе.
Во-вторых: CFML компилируется перед выполнением. Таким образом, процесс (для всех намерений и целей):
- Файл с кодом запрашивается
- Код из файла передается компилятору CF
- CF-компилятор выплевывает Java-байт-код
- JVM выполняет Java-байт-код
Таким образом, ваш код для генерации строки с кодом CFML не выполняется до (4), но он необходим обратно в (2). Если вы не можете путешествовать во времени, это не сработает.
Я обсуждаю это в своем блоге: " Процесс запроса / ответа ColdFusion"
Есть несколько вещей, которые вы можете сделать:
- не пишите динамический универсальный SQL, как это. Все мы делаем это, когда начинаем, но быстро понимаем, что динамический / универсальный SQL никогда не является хорошим решением для любой проблемы.
- Используйте один из уже существующих уровней абстракции БД. CF 9+ поставляется с поддержкой Hibernate.
- Если вы используете
Query.cfc
вместо<cfquery>
Вы можете добавить заполнители для параметров и передать данные параметров в запрос отдельно. - Запишите свой динамический код на диск, затем
include
Это. Это подорвет время компиляции / выполнения. Это будет медленно, так как ваш включенный файл должен быть скомпилирован перед запуском. Это ужасно.
Этот список в моем порядке предпочтения для решения этой проблемы.
Это ответ на вопрос: "В любом случае, мы можем динамически добавить cfqueryparam в запрос?". Есть, но вы должны сделать это внутри блока cfquery. Как то так нормально
<cfquery>
select SomeFields
from SomeTables
where 1 = 1
<cfif something>
and somefield = <cfqueryparam value="#SomeVariable#">
</cfif>
</cfquery>
То, что вы не можете сделать, по крайней мере, в версии 9 и ниже, это сделать параметры запроса частью переменной. Другими словами, это не скомпилируется.
WhereClause = "where 1=1";
if (something)
WhereClause &= ' and somefield = <cfqueryparam value="#SomeVariable#">';
Это более или менее то, что вы пытались.