Статьи

Некоторые недавние ColdFusion ORM Pain

Я работаю над относительно простым приложением ColdFusion ORM. Он сфокусирован на основном типе сущности под названием Content. Этот тип сущности довольно большой, около 50 или около того свойств. Как вы можете себе представить, некоторые свойства просты, некоторые — многие к одному, а некоторые — многие ко многим. Я столкнулся с некоторыми очень расстраивающими проблемами, и я думал, что поделюсь ими.

Invoke

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

var simpleList = "subsegment,topic,topicupdatedby,task,need";

for(var x=1; x lte listLen(simplelist); x++) {
	var li = listGetAt(simpleList, x);
	invoke(content, "set#li#", data[li]);
}

Просто, правда? Но обратите внимание на использование invoke. Это дополнение ColdFusion 10, которое позволяет вызывать динамические методы в CFC. Я заметил, что ни одна из моих данных на самом деле не сохраняется. Зачем?

Оказывается — для того, чтобы мои вызовы setX (где X — это метод сущностей) работали, я должен передать значение как структуру. Вот модификация:

for(var x=1; x lte listLen(simplelist); x++) {
	var li = listGetAt(simpleList, x);
	invoke(content, "set#li#", {"#li#"=data[li]});
}

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

Отчет об ошибках

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

Как я упоминал выше, моя сущность имеет простые свойства, свойства «многие к одному» и «многие ко многим». Я начал с кодирования в простых свойствах (используя технику, описанную выше). Затем я сделал много-к-одному. Затем я сделал много ко многим.

Я заметил, что моя таблица соединений не была заполнена. Я не получил ошибку, хотя. Что еще более расстраивает, так это то, что я мог сбросить свою сущность перед операцией сохранения и четко видеть связанные с ней данные в сущности. И все же я запустил сохранение, он вставил бы новую запись в основную таблицу и просто … больше ничего не делал. Опять же — ни черта ошибки. В любом месте.

Поэтому я немного отступил. Сначала я решил — давайте отключим функцию автоматического сброса и используем транзакции. Я не думал, что это поможет само по себе, я просто решил попробовать. Внезапно я получил что-то — ошибка:

coldfusion.orm.PersistentTemplateProxy не может быть приведен к java.util.Collection.

Хорошо … так что … сначала. Зачем ColdFusion сохранять сущность, иметь проблему и просто не сообщать об этом, пока я сам не начну обрабатывать сброс с транзакцией? Я не могу представить причину, почему это имело бы смысл.

Здесь все стало еще интереснее. Я закомментировал код, обрабатывающий многие ко многим, и все еще получил ошибку!

По какой-то причине я решил закомментировать код, обрабатывающий 3 моих свойства «многие к одному». Внезапно это решило проблему. Затем я раскомментировал «многие ко многим», и он все еще работал нормально (и сохранил данные в таблице соединений). Очевидно, моя проблема была в блоках «многие к одному».

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

public any function setSegment(id) {
	var segment = entityLoadByPk("segment", id);
	variables.segment = segment;
	writelog("added a segment");
	segment.setContent(this);
}

Просто, правда? В моей сущности контента я вызываю setSegment. Метод обрабатывает логику преобразования идентификатора в сущность, установки его и выполнения обратной стороны. Но что-то здесь было не так.

Однако мне ни разу не сказали, что случилось. За пределами сообщения об ошибке, которое я вставил выше, я был потерян.

Наконец я начал комментировать строки в этом методе и объяснил это так:

segment.setContent (это);

И тут меня осенило. Что касается контента, у него есть один сегмент. На стороне сегмента у него много сущностей контента.

Итак, я сразу понял, что встроенные методы, по-видимому, не проверяются в тех случаях, когда требуется массив.

Тьфу.