Как сохранить целое число с помощью ColdFusion ORM?

TL:DR;

Каков правильный синтаксис/обходной путь/хак для компонентов CF ORM, которые имеют ограничения внешнего ключа?


ColdFusion + Целые числа

Сохранение переменной в виде целого числа должно быть простым вопросом программирования, верно? Найдите соответствующую функцию в документации по языку (если вы не можете вспомнить ее сразу), которая будет говорить returns: int (owtte), и используйте ее.

Не с ColdFusion.

Некоторые из вас, возможно, уже знакомы с различные проблемы с целыми числами, но одна из них, которая в настоящее время вызывает у меня быстрое выпадение волос, заключается в том, что ColdFusion иногда сохраняет ваше "целое число" как строку, двойную или длинную. Теперь, в большинстве случаев использования, это не проблема, нарушающая функциональность, и ее часто упускают из виду/игнорируют/не обнаруживают. Исключением в моем случае является случай, когда в игру вступает ORM. Конечно, как и любой здравомыслящий разработчик, я признаю возможность того, что где-то это связано с ошибкой пользователя.


Проблема

Проблема возникает всякий раз, когда CF пытается взаимодействовать с БД. Если есть поле, которое является внешним ключом и имеет тип «целое число», CF выдает исключение Hibernate со следующим сообщением:

java.lang.Integer

Вот и все. Полезно, правда? Я обнаружил, что это «сообщение об ошибке» явно является типом переменной, которую вы передаете в это поле, поэтому, если вы ошибочно передадите двойное значение в поле, сообщение об ошибке будет читаться как java.lang.Double.

Теперь это, кажется, не столько о самом поле, сколько о связанных компонентах - это происходит только с полем, которое имеет ограничение внешнего ключа, связывающее его с целочисленным полем где-то еще.

Основной пример того, что я собираюсь сделать:

Шаблон.cfc

component persistent="true" table="template"{

    property name="id"              type="numeric"  sqltype="integer"   column="templateID" fieldtype="id"  generator="identity";
    property name="userID"          type="numeric"  sqltype="integer"   fkcolumn="userID"           fieldtype="many-to-one" cfc="User";
    property name="lastModified"    type="date"     sqltype="timestamp" column="lastModified";

}

User.cfc

component persistent="true" table="user"{

    property name="id"          type="numeric"  sqltype="integer"   column="userID"     fieldtype="id" generator="identity";
    property name="username"    type="string"   sqltype="nvarchar"  column="username";
    property name="password"    type="string"   sqltype="nvarchar"  column="password";

}

Проблема возникает при сбросе ORM с обновлением template.userID.


Вещи, которые я пробовал

  • Обращение в службу поддержки Adobe CF (у нас есть корпоративная лицензия с платиновой поддержкой, но за месяц они не смогли дать мне решение или даже какую-либо информацию, кроме «это не работает?»)
  • Добавление атрибута ormtype в поля идентификации (а затем в поля внешнего ключа, когда это не сработало)
  • Изменение свойства sqltype (которое, как я теперь считаю, предназначено только для создания таблицы, в котором мы никогда не нуждались, так как база данных уже была на месте)
  • Converting the variable using various combinations of the following functions:
    • NumberFormat( var ) - documentation says it returns 'A formatted number value', actually returns a java.lang.String
    • LSParseNumber( var )- возвращает двойной
    • Int( var ) – Это здорово: в документации сказано, что он возвращает целое число в виде строки. На самом деле возвращает java.lang.Double
    • Val( var ) - возвращает двойной
    • javaCast( 'int', var ) - возвращает целое число, которое выдает ту же ошибку
  • Установка атрибута elementtype для свойства (оба конца)
  • Ослабление атрибута validate в свойстве (оба конца) до «числового»

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


Окружающая обстановка

  • Windows Server 2012 R2
  • ColdFusion 2016 (предприятие)
  • SQL-сервер

person James Cushing    schedule 21.08.2017    source источник
comment
Является ли столбец, в котором вы сохраняете данные, целым числом?   -  person James A Mohler    schedule 21.08.2017
comment
В базе данных (среда обновлена ​​- спасибо за это) столбец int   -  person James Cushing    schedule 21.08.2017
comment
Если решение заключалось в обновлении БД, то это следует рассматривать как ответ.   -  person James A Mohler    schedule 22.08.2017
comment
Это не так, я просто сообщал вам, что столбец в базе данных int - спасибо за то, что помогли мне понять, что я еще не добавил БД в свою среду выше.   -  person James Cushing    schedule 22.08.2017


Ответы (1)


TL:DR;

Передайте сущность, а не идентификатор. Свойство внешнего ключа в CF ORM, ссылающееся на постоянный объект Foo, имеет тип Foo, а не int.

Подробнее

По прошествии всего этого времени Adobe передала мне несколько человек, пока я не наткнулся на инженера, который знал, о чем говорит. Оказывается, проблема не столько в том, что механизм ORM (Hibernate) не распознает целое число как целое, а в том, что если у вас есть внешний ключ, который ссылается на другой постоянный объект, вы должны передать сущность. а не удостоверение личности.

Пример (в контексте вопроса)

Во-первых, я удалил значения type и sqltype из вопроса, поскольку первое может быть получено с помощью CF, проверяющего БД (что в моем случае нормально, но вам, возможно, придется явно установить его, особенно если вы отключили useDBforMapping в Application.cfc).

Во-вторых, я переименовал свойство userID в компоненте Template в user, так как это может помочь тем, кто не сразу понял, что я сказал выше о «передаче объекта», лучше визуализировать его.

Шаблон.cfc

component persistent="true" table="template"{

    property name="id"              column="templateID"      fieldtype="id"          generator="identity";
    property name="user"            fkcolumn="userID"        fieldtype="many-to-one" cfc="User";
    property name="lastModified"    column="lastModified";

}

User.cfc

component persistent="true" table="user"{

    property name="id"          column="userID"     fieldtype="id" generator="identity";
    property name="username"    column="username";
    property name="password"    column="password";

}

Итак, допустим, вы знаете идентификатор пользователя, связанного с этим шаблоном (например, он может быть его создателем). Что вам нужно сделать, так это не передавать идентификатор свойству user, а создать компонент User, а затем передать это.

index.cfm

userID = 4; // Example user ID, which we got from somewhere earlier in the code

templateID = 20; // Example template ID, which we got from somewhere earlier in the code

// Create template entity (loading by primary key)
template = EntityLoadByPK( 'Template', templateID );

// To set the user in the Template entity, we must pass a User entity
user = EntityLoadByPK( 'User', userID );

// Only then can we successfully update the template's foreign key property
template.setUser( user );
EntitySave( template );

// Line below is not usually needed, but it forces DB interaction so it's 
// useful in the context of this example
ORMFlush();

Надеюсь, это поможет всем, кто сталкивается с той же путаницей.

JC

person James Cushing    schedule 31.08.2017