Coldfusion — ошибка сложного объекта при попытке выполнить cfloop по запросу. Несоответствие версий?

Преамбула: Итак, у нас есть несколько работающих приложений, которые нам нужно перенести на новый сервер, потому что мы выводим из эксплуатации старый, и в результате мне пришлось установить новый экземпляр CF.

Это приложение отлично работает на старом сервере, на котором работает версия ColdFusion "9,0,0,251028" Standard edition (через администратора ColdFusion).

На новом сервере я использую CF 2016 версии 2016.0.0.298074 Developer edition (это первое, что появилось в поиске Google, поэтому я выбрал его).

Теперь проблема: есть кусок кода, выдающий ошибку, которая говорит:

Сложные типы объектов не могут быть преобразованы в простые значения.

Выражение запросило переменную или результат промежуточного выражения как простое значение. Однако результат не может быть преобразован в простое значение. Простыми значениями являются строки, числа, логические значения и значения даты/времени. Запросы, массивы и COM-объекты являются примерами сложных значений. Наиболее вероятная причина ошибки в том, что вы пытались использовать сложное значение как простое. Например, вы пытались использовать переменную запроса в теге cfif.

Ошибка произошла в G:/Gumbo/components/modules/resource/ResourceAdmin.cfc: строка 282 Вызывается из G:/Gumbo/admin/modules/resource/action.cfm: строка 34 Вызывается из G:/Gumbo/admin/action .cfm: строка 19

281 cfloop query="getseq">
282 <cfif getseq.resourceCategoryID IS temp><cfset newseq = getseq.displaySeq ><cfbreak></cfif>
283 </cfloop>

Строка нарушения — 282. Рассматриваемый код:

<cfloop query="getseq">
      <cfif getseq.resourceCategoryID IS temp><cfset newseq = getseq.displaySeq ><cfbreak></cfif>
</cfloop>

Из моего исследования я заметил, что, по-видимому, cfloop не работает с параметрами запроса в некоторых версиях ColdFusion, но я не понимаю, почему НОВАЯ версия вызывает у меня эту ошибку.

Итак, мой вопрос:

  1. Есть ли способ как-то восстановить эту старую версию CF? Имейте в виду, что у меня есть исходная папка CF9 на моем старом компьютере, но я не был уверен, есть ли способ взять исходные файлы и переместить их или установить вручную, или все тонкости этого. Может ли это быть таким же простым, как копирование старых исходных файлов в новый источник CF на более новом сервере?

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

Любое понимание будет оценено.

РЕДАКТИРОВАТЬ:

Вот вся оскорбительная функция:

<cffunction name="updateResource" access="public" output="false" displayname="Update a Resource">       
    <cfset VARIABLES.dateUpdated=DateAdd("d", 0, arguments.dateUpdated)>    

    <cfquery datasource="#this.datasource#">
      update md_rlm_resource
      set published=<cfqueryparam cfsqltype="cf_sql_tinyint" value="#arguments.published#">,
          resourceName=<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.resourceName#">,
          resourceNumber=<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.resourceNumber#">,
          resourceAuthor=<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.resourceAuthor#">,
          resourceFile=<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.resourceFile#">,
          dateUpdated=<cfqueryparam cfsqltype="cf_sql_timestamp" value="#VARIABLES.dateUpdated#">,
          shortDescription=<cfqueryparam cfsqltype="cf_sql_longvarchar" value="#arguments.shortDescription#">
      where resourceID=<cfqueryparam value="#arguments.resourceID#" cfsqltype="cf_sql_integer">
    </cfquery>    

    <cfquery name="getseq" datasource="#this.datasource#">
      select displaySeq, resourceCategoryID
      from md_rlm_resourcecategoryrel
      where resourceID=<cfqueryparam value="#arguments.resourceID#" cfsqltype="cf_sql_integer">   
    </cfquery>

    <cfquery datasource="#this.datasource#">
      delete from md_rlm_resourcecategoryrel
      where resourceID=<cfqueryparam value="#arguments.resourceID#" cfsqltype="cf_sql_integer">
    </cfquery>

    <cfif IsDefined("arguments.resourceCategoryIDs")>
      <cfset resourceCategoryID = ArrayNew(1)>
      <cfset resourceCategoryID = ListToArray(arguments.resourceCategoryIDs)>

      <cfif #ListLen(arguments.resourceCategoryIDs)# gt 1>
        <cfset tmp1 = #ArrayLen(resourceCategoryID)#>
        <cfelse>
        <cfset tmp1 = "1">
      </cfif>

      <cfloop INDEX="idx" FROM="1" TO="#tmp1#">     
        <cfset newseq = 1>

        <cfif #tmp1# gt 1>
           <cfset temp=resourceCategoryID[idx]>
        <cfelse>
           <cfset temp=resourceCategoryID>        
        </cfif>

        <cfloop query="getseq">
          <cfif getseq.resourceCategoryID IS temp><cfset newseq = getseq.displaySeq ><cfbreak></cfif>
        </cfloop>

        <cfquery datasource="#this.datasource#">
          insert into md_rlm_resourcecategoryrel
             (resourceCategoryID, resourceID, displaySeq)
          values
            (
            <cfif #tmp1# gt 1>
            <cfqueryparam CFSQLTYPE="cf_sql_integer" VALUE="#resourceCategoryID[idx]#">,
            <cfelse>
            <cfqueryparam CFSQLTYPE="cf_sql_integer" VALUE="#resourceCategoryID#">,
            </cfif>       
             <cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.resourceID#">,
             <cfqueryparam cfsqltype="cf_sql_float" value="#newseq#">)
        </cfquery>
      </cfloop>   
    </cfif> 

    <cfquery datasource="#this.datasource#">
    DELETE FROM md_rlm_resourceregionrel 
    WHERE resourceID=<cfqueryparam value="#arguments.resourceid#" cfsqltype="cf_sql_integer">
    </cfquery>

    <cfloop index="regionele" list="#arguments.regionID#" delimiters=",">
        <cfquery datasource="#this.datasource#">
        INSERT INTO md_rlm_resourceregionrel (resourceID, regionID) 
        VALUES (<cfqueryparam value="#arguments.resourceid#" cfsqltype="cf_sql_integer">, #regionele#)
        </cfquery>
    </cfloop>
</cffunction>

person Cody Rogers    schedule 01.03.2016    source источник
comment
Вы можете найти заархивированную версию ColdFusion на cfrepo gpickin.com/cfrepo Что касается вашей ошибки, что такое temp ? если вам нужно увидеть, что такое переменные, вы можете сделать cfdump, чтобы проверить их.   -  person John Whish    schedule 01.03.2016
comment
temp — это resourceCategoryID, полученный из другой таблицы базы данных и сравниваемый, чтобы убедиться, что идентификаторы совпадают, насколько я могу судить. Насколько я понимаю, это не способствует проблеме, потому что в другой версии все работает нормально. Проверяю репо сейчас, спасибо за рекомендацию!   -  person Cody Rogers    schedule 01.03.2016
comment
Мы находимся в середине той же миграции (CF 9 на 2016). Я бы посоветовал вам сосредоточиться на рефакторинге вашей кодовой базы для устранения подобных несоответствий, а не придерживаться более старой версии CF. Вы выводили содержимое каждой строки запроса и значение temp для каждой итерации цикла? К 2016 году у вас могут быть неверные данные, которые интерпретируются по-другому. Мы сталкивались с такими вещами, как неверный синтаксис функций, который работает в CF 9, но не в 2016 году. У нас есть проект, специально предназначенный для устранения подобных несоответствий в коде, прежде чем мы выпустим 2016 год в производство.   -  person Adrian J. Moreno    schedule 01.03.2016
comment
Можете ли вы дать нам точную ошибку, скопируйте и вставьте с экрана, а не перефразируйте. Ошибка на экране также покажет точное выражение, вызвавшее ошибку, и оно не из кода, который вы нам дали здесь. Также, когда вы говорите, я заметил, что, по-видимому, cfloop не работает с параметрами запроса ... где вы говорите параметр, вы имеете в виду атрибут? Как вы думаете, <cfloop query> сам по себе не работает на какой-то версии CF? Это не тот случай. Если только в CF2016 не была введена новая ошибка (вполне вероятно). Наконец, вы можете дать нам надлежащий автономный репродукционный случай этого?   -  person Adam Cameron    schedule 01.03.2016
comment
Отредактировано, чтобы включить полное сообщение об ошибке и фрагмент кода всей функции. По сути, функция редактирует ресурс через нашу CMS, а затем обновляет связанные базы данных.   -  person Cody Rogers    schedule 01.03.2016


Ответы (1)


Из этого:

<cfset resourceCategoryID = ListToArray(arguments.resourceCategoryIDs)>
...
<cfif #tmp1# gt 1>
    <cfset temp=resourceCategoryID[idx]>
<cfelse>
    <cfset temp=resourceCategoryID><!--- temp is now an array --->        
</cfif>

temp (ужасное имя переменной, кстати) может быть массивом.

И позже вы делаете это:

<cfif getseq.resourceCategoryID IS temp>

Вы не можете сравнивать массивы с помощью оператора IS: IS сравнивает простые значения. Вот почему вы видите ошибку.

Кроме того, вы не var используете ни одну из своих переменных в этом коде, что является довольно плохой формой и может привести к «неожиданному поведению» в вашем коде.

person Adam Cameron    schedule 02.03.2016
comment
Спасибо вам за разъяснение! Я унаследовал этот код, и я согласен с тем, что форма ужасна, плюс я не знаю холодного слияния, поэтому отлаживать его было непросто. Я ищу решения для сравнения сложных типов данных, и я вижу, что есть команды EQUAL и EQ, подойдет ли какая-либо из них для массивов? Или мне нужно преобразовать массив в список, а затем сравнить? Кроме того, почему вы подозреваете, что эта ошибка не возникает в более старой версии CF, такой как 9? - person Cody Rogers; 02.03.2016
comment
EQ и EQUAL и IS — это одни и те же операторы. Почему это может работать на более старой версии? Точно сказать не могу. Возможно - по какой-то причине у меня нет доступа к коду - он всегда попадает в ветвь true этого оператора if. Вы можете использовать oneArray.equals(anotherArray) для сравнения двух массивов? (ссылка: docs.oracle.com/javase/8/docs/api/java/util/) - person Adam Cameron; 02.03.2016
comment
Хотя equals(...) может работать, это, вероятно, не лучший вариант IMO. Причина в том, что это НАМНОГО более чувствительно, чем обычное сравнение CF. Обычно equals() также учитывает чувствительность к регистру и тип данных значения. Например, элемент 123 будет считаться отличным от val(123). - person Leigh; 07.03.2016