22.03.2016, 10:41 | #1 |
Участник
|
Опасный orig
Привет всем.
Хочу обсудить особенность работы метода orig. Суть в том что при создании записи из клиентского кода, при передаче буфера на сервер, common.orig() начинает возвращать тот же буфер, что может приводить к неприятным глюкам. Очевидно это баг/фича при репликации буферов между клиентом и сервером. Понимаю, что описано немного сумбурно, поэтому во вложении пример. Буфер заполняем в джобе GRD_TestOrig (джоб работает на клиенте). Далее при исполнении на клиенте все ок, orig() возвращает пустой буфер, но при переходе исполнения на сервер (например внутри метода Insert() который всегда на сервере исполняется), orig() начинает возвращать непустой буфер равный текущему. Из-за этого могут некорректно работать модификации закладывающиеся на сравнение значений полей в буфере с его orig() значениями. В стандарте похоже эту багофичу учитывали, поэтому и написан такой код: \Classes\InventUpd_Estimated\initUpdate X++: //AOSRunMode::Server void initUpdate() { ... movement_Orig = movement.newMovement_Orig(); ... } X++: InventMovement newMovement_Orig() { InventMovement movement_orig; if (this.buffer().RecId) { if (this.childBuffer().RecId) movement_orig = InventMovement::construct(this.buffer().orig(),this.inventMovSubType(),this.childBuffer().orig()); else movement_orig = InventMovement::construct(this.buffer().orig(),this.inventMovSubType()); } return movement_orig; // по факту пустой буфер принудительно возвращен а не orig() } \Classes\InventMov_Sales\newMovement_Orig X++: InventMovement newMovement_Orig() { if (salesOrderLine.RecId) return new InventMov_Sales(salesOrderLine.orig()); else return null; // а здесь не заморачивались, а просто вернули null вместо orig() } Вопросы такие : 1. Интересно, почему так сделано в ядре? Баг, который стал фичей или для чего-то нужно ? 2. Как это можно быстро исправить для кучи модификаций без переделки кода ? (к сожалению метод orig() на каждом буфере перекрывать утомительно да и невозможно - он final. А на common и xRecord нельзя свой код писать ) - пока мне кажется что быстро не исправить, придется тупо везде заменять вызовы orig() на свои костыли. Последний раз редактировалось Logger; 22.03.2016 в 11:12. Причина: Исправил опечатки |
|
|
За это сообщение автора поблагодарили: gl00mie (2), ex3em (1). |
22.03.2016, 11:26 | #2 |
Участник
|
Костыль пока вот такой
\Classes\Global\getOrig X++: //pkoz 22.03.2016 public static Common getOrig(Common _comon) { Common ret; ; ret = _comon.orig(); if (_comon.RecId == 0 ) { ret.doClear(); } return ret; } |
|
22.03.2016, 11:29 | #3 |
Участник
|
Смотри также оригинальный orig
|
|
|
За это сообщение автора поблагодарили: Logger (2). |
22.03.2016, 11:49 | #4 |
Участник
|
Цитата:
Сообщение от Logger
при создании записи из клиентского кода, при передаче буфера на сервер, common.orig() начинает возвращать тот же буфер, что может приводить к неприятным глюкам. при исполнении на клиенте все ок, orig() возвращает пустой буфер, но при переходе исполнения на сервер (например внутри метода Insert() который всегда на сервере исполняется), orig() начинает возвращать непустой буфер равный текущему. Из-за этого могут некорректно работать модификации закладывающиеся на сравнение значений полей в буфере с его orig() значениями. Как это можно быстро исправить для кучи модификаций без переделки кода?
|
|
22.03.2016, 12:41 | #5 |
Участник
|
Цитата:
если поля в текущем буфере и в orig различаются, выполняет какую-то дополнительную логику
Удивительно, что так долго бага не проявлялась. |
|
13.11.2017, 16:28 | #6 |
Участник
|
Странно.
Глюк проявился на форме PurchAgreement в 2012-й аксапте при редактировании условий оплаты AgreementHeaderDefault.PaymentSchedule Для обхода бага в write датасорса вместо super() приходится вызывать свой метод, передавая в него буфер датасорса. X++: // pkoz 13.11.2017 public server static void writeSafe_MRC(Common _common) { Common common4Save; DictTable dictTable; ; dictTable = New DictTable(_common.TableId); if (!dictTable || (!dictTable.hasRecidIdx() && !dictTable.hasSurrogateKey())) { throw error(Error::wrongUseOfFunction(funcname())); } ttsBegin; common4Save = dictTable.makeRecord(); if (_common.RecId) { select forupdate common4Save where common4Save.RecId == _common.RecId; } else { common4Save.clear(); } buf2Buf(_common, common4Save); common4Save.write(); ttsCommit; _common.reread(); } Кто-нибудь встречал такое на формах ? |
|
13.11.2017, 17:16 | #7 |
Участник
|
в коде нигде doinsert или doUpdate нету?
|
|
13.11.2017, 18:11 | #8 |
Участник
|
Нет.
Кастомизации минимальны и с этим не связаны. Это точно бага с orig Я дописал проверочный код который выводит в инфолог значение поля из буфера и из буфер.orig() - значения одинаковые, хотя реально они разные. Возможно как-то outer join датасорсов повлиял. |
|
|
За это сообщение автора поблагодарили: mazzy (2). |