AXForum  
Вернуться   AXForum > Microsoft Dynamics AX > DAX: Программирование
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 22.03.2016, 10:41   #1  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,941 / 3229 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
? Опасный orig
Привет всем.

Хочу обсудить особенность работы метода orig.
Суть в том что при создании записи из клиентского кода, при передаче буфера на сервер, common.orig() начинает возвращать тот же буфер, что может приводить к неприятным глюкам. Очевидно это баг/фича при репликации буферов между клиентом и сервером.
Понимаю, что описано немного сумбурно, поэтому во вложении пример.

Буфер заполняем в джобе GRD_TestOrig (джоб работает на клиенте).
Далее при исполнении на клиенте все ок, orig() возвращает пустой буфер, но при переходе исполнения на сервер (например внутри метода Insert() который всегда на сервере исполняется), orig() начинает возвращать непустой буфер равный текущему.

Из-за этого могут некорректно работать модификации закладывающиеся на сравнение значений полей в буфере с его orig() значениями.

В стандарте похоже эту багофичу учитывали, поэтому и написан такой код:

\Classes\InventUpd_Estimated\initUpdate
X++:
//AOSRunMode::Server
void initUpdate()
{
...
movement_Orig = movement.newMovement_Orig();
...
}
\Classes\InventMovement\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() на свои костыли.
Вложения
Тип файла: xpo SharedProject_GRD_TestOrig_2016_03_22_10_21_NEW_DEV_sapp901_2717.xpo (5.8 Кб, 325 просмотров)

Последний раз редактировалось Logger; 22.03.2016 в 11:12. Причина: Исправил опечатки
За это сообщение автора поблагодарили: gl00mie (2), ex3em (1).
Старый 22.03.2016, 11:26   #2  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,941 / 3229 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 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;
}
С его использованием все ок.
Вложения
Тип файла: xpo SharedProject_GRD_TestOrig_2016_03_22_11_25_NEW_DEV_sapp901_2717.xpo (7.0 Кб, 269 просмотров)
Старый 22.03.2016, 11:29   #3  
S.Kuskov is offline
S.Kuskov
Участник
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
3,438 / 1775 (66) ++++++++
Регистрация: 28.04.2007
Адрес: Калуга
Смотри также оригинальный orig
За это сообщение автора поблагодарили: Logger (2).
Старый 22.03.2016, 11:49   #4  
gl00mie is offline
gl00mie
Участник
MCBMSS
Most Valuable Professional
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,684 / 5798 (201) ++++++++++
Регистрация: 28.11.2005
Адрес: Москва
Записей в блоге: 3
Цитата:
Сообщение от Logger Посмотреть сообщение
при создании записи из клиентского кода, при передаче буфера на сервер, common.orig() начинает возвращать тот же буфер, что может приводить к неприятным глюкам. при исполнении на клиенте все ок, orig() возвращает пустой буфер, но при переходе исполнения на сервер (например внутри метода Insert() который всегда на сервере исполняется), orig() начинает возвращать непустой буфер равный текущему. Из-за этого могут некорректно работать модификации закладывающиеся на сравнение значений полей в буфере с его orig() значениями. Как это можно быстро исправить для кучи модификаций без переделки кода?
Багофича, конечно, неприятная, но масштаб бедствий вроде не такой большой, как кажется. Ведь влияет эта багофича только на код, который
  • вызывается и на вставке новых записей, и при обновлении существующих
  • работает на сервере, вызываясь напрямую или опосредованно из клиентского кода
  • различает вставку записей и их обновление неявно по тому, что те или иные поля, отличные от RecId, не заполнены в orig (например, SalesTable.orig().CustAccount)
  • если поля в текущем буфере и в orig различаются, выполняет какую-то дополнительную логику
Т.е. проблема, как мне кажется, не столько в багофиче, сколько в том, что некий код полагается на различие полей как неявный признак вставки новой записи. По идее такого кода должно быть не очень много.
Старый 22.03.2016, 12:41   #5  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,941 / 3229 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Цитата:
если поля в текущем буфере и в orig различаются, выполняет какую-то дополнительную логику
Ну вообще у нас любили так писать код. Это удобно. Пишешь код, который не смотрит на то, что идет - вставка или обновления, а тупо сравнивает различия.
Удивительно, что так долго бага не проявлялась.
Старый 13.11.2017, 16:28   #6  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,941 / 3229 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Странно.
Глюк проявился на форме 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();
}
Причина проблем все та же. Портится orig() значение буфера.

Кто-нибудь встречал такое на формах ?
Старый 13.11.2017, 17:16   #7  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от Logger Посмотреть сообщение
Кто-нибудь встречал такое на формах ?
в коде нигде doinsert или doUpdate нету?
__________________
полезное на axForum, github, vk, coub.
Старый 13.11.2017, 18:11   #8  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,941 / 3229 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Нет.
Кастомизации минимальны и с этим не связаны.

Это точно бага с orig
Я дописал проверочный код который выводит в инфолог значение поля из буфера и из буфер.orig() - значения одинаковые, хотя реально они разные.
Возможно как-то outer join датасорсов повлиял.
За это сообщение автора поблагодарили: mazzy (2).
Теги
orig, баг

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
оригинальный orig Wamr DAX: Программирование 7 17.02.2015 17:29
sashanazarov: Dynamics AX 2012: orig() method fails on derived tables Blog bot DAX Blogs 0 27.01.2014 19:12
Где определены табличные методы orig() и clear() bodeaux DAX: Программирование 1 15.10.2012 15:43
Утечка памяти при вызове orig() gb20 DAX: Программирование 3 11.12.2009 12:11
Глюк orig() в 3-tier или я чего-то не понимаю? olesh DAX: Программирование 2 26.07.2007 13:09

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 12:10.