Использование coldfusion.sql.QueryTable.next () в Coldfusion 9 - PullRequest
2 голосов
/ 06 июля 2011

Я пытаюсь написать пользовательский тег, который будет перебирать объект cfquery особым образом.Я нашел эту страницу: http://www.zrinity.com/developers/mx/undocumentation/query.cfm, в которой рассказывается, как использовать базовые java-методы для навигации по набору результатов, но, похоже, он не работает в CF9.

Я могу позвонить .next(),.previous(), .first() и .last() просто отлично, и каждый метод обновляет query.currentRow, но ссылка query.columnName всегда возвращает значение из первой строки, а не currentRow.

Пример:

<cfquery name="testQuery" datasource="source">
  SELECT FooName FROM NumberedFoos
</cfquery>

<cfloop from="1" to="3" index="i">
  <cfoutput>#testQuery.currentRow# =&gt; #testQuery.fooName#</cfoutput><br />
  <cfset testQuery.next()>
</cfloop>

Производит:

1 => Foo 1
2 => Foo 1
3 => Foo 1

Я знаю, что могу использовать что-то вроде testQuery.fooName[testQuery.currentRow], но это довольно нежелательно для людей, для которых я создаю пользовательский тег.Была ли удалена функциональность, описанная в приведенной выше ссылке из CF9?Если да, есть ли альтернатива?

EDIT

Чтобы подробнее узнать, почему, клиенту нужен собственный тег, который позволяет ему "утверждать" определенные вещи в запросе.Клиент имеет довольно низкий уровень понимания CF, но довольно хорошо пишет SQL.Их желаемый конечный результат является чем-то похожим на:

<cfquery name="purchaseTotals">
  SELECT PurchaseId, Total FROM Purchases
</cfquery>

<CF_ASSERT query="purchaseTotals">
  purchaseTotals.Total gte 0
</CF_ASSERT>

Желаемым результатом будет html-таблица, где каждая строка является строкой из запроса, который не соответствует утверждению.Поэтому для меня тег CF_ASSERT должен иметь возможность обновлять текущую строку.

Редактировать 2:

Основная задача - разрешить использование html в теле тега, сохраняя при этом запросзначения подставляются из соответствующей строки:

<CF_ASSERT query="purchaseTotals">
  <CF_CONDITION expression="purchaseTotals.Total gte 0">
    <!---error message when expression is false--->
    <cfoutput>
      Purchase #purchaseTotals.purchaseId# has a negative total!
    </cfoutput>
  </CF_CONDITION>
  <CF_CONDITION expression="purchaseTotals.Total eq ''">
    #PurchaseTotals.purchaseId# has a null total, this may be caused by:
    <ul>
      <li>Edge Case 1</li>
      <li>Edge Case 2</li>
    </ul>
  </CF_CONDITION>
<CF_ASSERT>

Вывод здесь будет выглядеть примерно так:

  Purchase 120 has a negative total!
  Purchase 157 has a negative total!
  Purchase 157 has a null total, this may be caused by:
<ul><li>Edge Case 1</li><li>Edge Case 2</li></ul>

Ответы [ 2 ]

2 голосов
/ 15 июля 2011

Была ли удалена функциональность, описанная в приведенной выше ссылке из CF9?

Внутренний материал определенно изменился с тех пор, как статья была написана в 2006 году. Но я подозреваю, что описанная вами точная функциональность может отсутствовать ни в одной версии mx. Ключевым отличием вашего кода от связанных примеров является использование <cfoutput query=".."> (а не просто <cfoutput>). Атрибут query, очевидно, обеспечивает некоторый дополнительный контекст при оценке переменных. Удалите его (как в вашем примере), и результатом будет «значение из первой строки, а не currentRow.». Даже под MX6, что не сулит ничего хорошего для последующих версий. Эта точная функциональность, вероятно, не была удалена. Просто он никогда не работал с самого начала.

Если так, есть ли альтернатива?

Как я уже говорил ранее, самым чистым подходом было бы использование понятия массива, т.е. #query.column[row]#. Учитывая, что вы, кажется, отклонили эту опцию, у вас в основном остается evaluate(). Вам нужно будет перебрать запрос внутри родительского тега. Затем используйте evaluate для обработки выражения и содержимого подтэга. Это не особенно элегантно или просто ИМО. Но я думаю, что это может быть хорошо, так как получается без обозначений массивов или какой-то ритуальной жертвы.

ASSERT.cfm

<cfparam name="attributes.query" type="string">

<cfif thisTag.ExecutionMode is 'start'> 
    <!--- validate attributes.query is a query object --->
    <cfif not ( structKeyExists(caller, attributes.query) AND IsQuery(caller[attributes.query]) )>
        <cfthrow message="Attributes.query [#attributes.query#] is undefined or not a query object">
    </cfif>
</cfif>
<cfif thisTag.ExecutionMode is 'end'> 
    <cfset variables[attributes.query] = caller[attributes.query]> 
    <cfloop query="variables.#attributes.query#">
        <cfloop array="#thisTag.assocAttribs#" index="subTag">
            <cfset variables.matchFound = evaluate(subTag.expression)>
            <cfif variables.matchFound>
                <cfoutput>[#currentRow#] #evaluate(DE(subTag.Content))#</cfoutput><hr>
            </cfif>
        </cfloop>
    </cfloop>
</cfif>

CONDITION.cfm
Примечание: НЕ используйте <cfoutput> теги в содержимом тега.

<cfparam name="attributes.expression" type="string">
<cfif thisTag.ExecutionMode is "start"> 
    <cfassociate baseTag="CF_ASSERT">
</cfif>
<cfif thisTag.ExecutionMode is "end"> 
    <cfset attributes.content = thisTag.GeneratedContent>
    <cfset thisTag.GeneratedContent = "">
</cfif>

клиент имеет довольно низкий уровень понимания CF, но довольно сплошное написание SQL

Сказав все это, вещи реализуются таким образом, потому что это лучший подход или потому что это наиболее похоже на написание SQL, т.е. удобно?

1 голос
/ 09 июля 2011

Классический пример эффекта внутренней платформы.

Я бы посоветовал вам не делать этого, поскольку вы пытаетесь создать систему, которая имитирует встроенную функциональность базовой или работающей системы, которая в конечном итоге становится плохо реализованной версией системы, в которой она запущена / реализована.

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

Смотрите здесь для получения дополнительной информации: http://en.wikipedia.org/wiki/Inner-platform_effect

P.s. что вы ищете (хотя я не согласен с реализацией) - это изменение запроса вне cfloop, просто используйте синтаксис массива:

#queryName.fieldName[rowNumber]#

Используя это, вы можете запросить запрос так, как пожелаете, конечно же, нет необходимости в базовом Java. Обратите внимание, что мы не используем queryName.currentRow. Для предыдущей () функции next () вы просто меняете rowNumber вверх или вниз.

...