Как установить имя динамического ключа в структуре с столбцом cfquery?

У меня есть структура, в которой я хочу заменить ключ currentRow столбцом cfquery recID. Этот столбец представляет собой целое число, которое автоматически увеличивается в таблице sql. По какой-то причине мой код не может создать структуру с уникальным ключом. Вот мой код:

<cfquery name="qryAccounts" datasource="myDB">
   SELECT RecID, FirstName, LastName
   FROM Accounts WITH (NOLOCK)
</cfquery>

<cfloop query="qryAccounts">
    <cfset fnAccounts[RecID] = StructNew()>
    <cfset fnAccounts[RecID].RecordID = RecID>
    <cfset fnAccounts[RecID].FirstName = FirstName>
    <cfset fnAccounts[RecID].LastName = LastName>
</cfloop>

Код выше дал такой результат:

[
  {
    "FIRSTNAME": "Mike",
    "LASTNAME": "Richards",
    "RECORDID": 1
  },
  null,
  null,
  null,
  {
    "FIRSTNAME": "John",
    "LASTNAME": "Matt",
    "RECORDID": 6
  }
]

Затем я попытался сделать это:

<cfquery name="qryAccounts" datasource="myDB">
   SELECT RecID, FirstName, LastName
   FROM Accounts WITH (NOLOCK)
</cfquery>

<cfloop query="qryAccounts">
    <cfset fnAccounts["ID"&RecID] = StructNew()>
    <cfset fnAccounts["ID"&RecID].RecordID = RecID>
    <cfset fnAccounts["ID"&RecID].FirstName = FirstName>
    <cfset fnAccounts["ID"&RecID].LastName = LastName>
</cfloop>

И код выше дал правильный вывод:

{
  "ID1": {
  "FIRSTNAME": "Mike",
  "LASTNAME": "Richards",
  "RECORDID": 1
  },
"ID6": {
  "FIRSTNAME": "John",
  "LASTNAME": "Matt",
  "RECORDID": 6
  }
}

Мне интересно, почему первый код не дает правильного вывода? Почему вторая версия с добавленной строкой работает нормально? Есть ли способ исправить или обойти эту проблему?


person espresso_coffee    schedule 16.05.2018    source источник
comment
Просто примечание: убедитесь, что вам нужно и понимаете, что делает WITH (NOLOCK). Добавлять его в запросы не всегда хорошо, и это может привести к тому, что ваш запрос вернет неправильные результаты. Кроме того, начиная с SQL 2005 в этом обычно нет необходимости.   -  person Shawn    schedule 17.05.2018
comment
@Shawn Я не использую блокировку, чтобы таблица оставалась доступной, если несколько пользователей пытаются получить доступ к данным. Я не уверен, что с SQL 2008 это все еще необходимо.   -  person espresso_coffee    schedule 17.05.2018
comment
Обычно для этого и используется. Мое единственное предостережение - убедиться, что с вами все в порядке, если вы читаете грязные данные. NOLOCK совпадает с READ UNCOMMITTED и позволит выполнить ваш запрос, пока пользователь вставляется, но тогда ваша структура может вызвать проблемы, если вставленный пользователь откатывается и удаляется из вашей базы данных. Если у вас возникли проблемы с блокировкой таблицы Accounts, возможно, вы захотите изучить причины блокировки, а не скрывать ее с помощью NOLOCK.   -  person Shawn    schedule 17.05.2018


Ответы (3)


Все, что вам нужно сделать, это определить переменную fnAccounts как структуру.

<cfset fnAccounts = {}>

Без определения CF имеет право выбирать то, что кажется подходящим.

<cfquery name="qryAccounts" datasource="myDB">
   SELECT RecID, FirstName, LastName
   FROM Accounts WITH (NOLOCK)
</cfquery>

<cfset fnAccounts = {}>
<cfloop query="qryAccounts">
    <cfset fnAccounts[RecID] = StructNew()>
    <cfset fnAccounts[RecID].RecordID = RecID>
    <cfset fnAccounts[RecID].FirstName = FirstName>
    <cfset fnAccounts[RecID].LastName = LastName>
</cfloop>

Поскольку вы пытаетесь использовать RecID в качестве ключа целочисленного значения, это похоже на то, как мы обращаемся к массиву (fnAccounts[1] первая позиция в массиве). Как только вы определили fnAccounts как структуру, ColdFusion может рассматривать переменную как структуру.

ДЕМО

person rrk    schedule 16.05.2018
comment
Спасибо за решение. Я немного запутался, потому что нам нужно дважды определить структуру... Это только из-за способа ColdFusion получить значение из массива или чего-то еще? - person espresso_coffee; 16.05.2018
comment
Он определяется только один раз. Код внутри цикла не определяет fnAccounts. Он просто добавляет ценности. - person SOS; 16.05.2018
comment
Это имеет смысл. Код внутри просто устанавливает ключ для текущей строки. Спасибо еще раз. - person espresso_coffee; 16.05.2018
comment
@espresso_coffee - Небольшое уточнение. fnAccounts = {} явно указывает CF определить переменную как структуру. Принимая во внимание, что fnAccounts[RecID] инструктирует CF создать переменную (если необходимо) и использовать наилучшее предположение о типе. Если RecID является целым числом (1,12,14,...), CF считает его позицией в массиве и создает массив. В противном случае он создает структуру. - person SOS; 16.05.2018
comment
@Ageax Итак, мы должны объявить fnAccounts = {} в случае, если ключ является целым числом, иначе CF воспримет это как массив. Верный ? - person espresso_coffee; 16.05.2018
comment
@espresso_coffee - Правильно. Хотя ИМО, рекомендуется заявить об этом заранее и исключить догадки. - person SOS; 17.05.2018
comment
Мне кажется, было бы более разумно, чтобы fnAccounts был массивом структур, а не структурой структур? - person Scott Stroz; 17.05.2018
comment
@ScottStroz Да, но все зависит от того, как вы запланировали получить к нему доступ. Но всегда есть более чем один способ сделать что-то. - person rrk; 17.05.2018

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

<cfscript>
    function queryToArray(q) {
        var ret = [];
        var cols = listToArray( q.columnList );
        for(var i in q) {
            var row = {};
            for(var col in cols ) {
                row[lcase(col)] =  i[col];
            }
            arrayAppend(ret, row);
        }
        return ret;
    }
</cfscript>

Помещение данных в массив структур (вместо структуры, если структуры) кажется мне более интуитивно понятным при обращении к данным запроса.

person Scott Stroz    schedule 17.05.2018
comment
массив структур (вместо структуры, если структуры) кажется более интуитивным Я согласен, если только нет особой необходимости искать данные по уникальному ключу. - person SOS; 17.05.2018
comment
Мне нравится использование columnList для гибкости - person James A Mohler; 17.05.2018

Мое решение основано на RRK, но мне больше нравится cfscript

<cfquery name="qryAccounts" datasource="myDB">
  SELECT RecID, FirstName, LastName
  FROM Accounts WITH (NOLOCK)
</cfquery>

<cfscript>
  fnAccounts = {};
  for (i in qryAccounts) {
     fnAccounts[i.RecID] = {
       RecordID : i.RecID,
       FirstName : i.FirstName,
       LastName : i.LastName
       };
     } // end for 
</cfscript>

cfquery тоже можно перенести в cfscript

person James A Mohler    schedule 17.05.2018
comment
Также обратите внимание на более изящный синтаксис для создания структур { RecordID : "value", FirstName : "value", ....} - person SOS; 17.05.2018