Показать сообщение отдельно
Старый 16.03.2023, 14:55   #4  
Player1 is offline
Player1
Участник
Самостоятельные клиенты AX
 
305 / 137 (5) +++++
Регистрация: 21.04.2008
Цитата:
Сообщение от fed Посмотреть сообщение
В общем - дело давнее: Насколько я помню, в стандартном сводном DAX2009 была бага, связанная с кэшированием чистых потребностей. Когда происходит вызов reqTrans.update() туда как второй (насколько я помню) параметр передается ссылка на класс ReqTransCache, где кэш с чистыми потребностями хранится. И после обновления, reqTrans.update() складывает в reqTransCache обновленную копию записи.

При этом где-то как раз в недрах методов deleteExplosionCoverage и deleteExplosionCoverageTrans этот второй параметр не передается и в reqTransCache остаются необновленные данные, при использовании которых и случается updateConflict. (На самом деле - там не update conflict в чистом виде, а просто попытка записать в БД устаревшую копию записи, с неверным recVersion). Я это лечил простым способом - при вызове цепочки deleteExplosion() я новым параметром передавал ReqTransCache и дальше передавал его глубже в reqTrans.update() (и возможно в reqTrans.delete() и reqTrans.insert() - я уже не помню есть там такой параметр или нет). После того как я это сделал, проблема вылечилась и система у клиента уже 12 лет работает.

P.S. Поправка - судя по коду D365FO передается не reqTransCache, а reqPlanData. Но из reqPlanData внутри update вынимается ReqTransCache и туда обновленные данные складываются. Но в целом - подход к решению это не меняет. Над убедится что из deleteExplosion* в метод update передается ссылка на правильный класс.
Хмм, спасибо огромное, но судя по всему всё так и передается
В ReqTrans.update()
X++:
public server void update(ReqPlanData _reqPlanData = null,
                          boolean _reduceCovQty = true)
{
    ReqTransCache           reqTransCache = _reqPlanData ? _reqPlanData.reqTransCache() : null;
а после super()
X++:
    if (reqTransCache)
        reqTransCache.update(this);
Методы deleteExplosionCoverage(Trans) просто протаскивают через себя необязательный параметр
X++:
server void deleteExplosionCoverageTrans(ReqPlanData     _reqPlanData             = null)
Ну а по стеку эта цепочка начинается в ReqCalc.deleteItemRequirement(), но там идет передача
X++:
        if (reqTrans.isDerivedDemand())
        {
            // reqTrans has to be updated but it could be it has been derived deleted by the previous record in this select statement
            // we need to ensure the record still exists
            if (   reqTransCache.exists(reqTrans)
                || ReqTrans::findRecId(reqTrans.RecId).RecId)
            {
                reqTrans.CovQty = 0;
                reqTrans.update(reqPlanData);
            }
        }
        else
        if (reqTrans.isPlannedOrder())
        {
            setupDim = reqPlanData.newReqSetupDim(_setup,reqTrans.CovInventDimId);

            if (reqPlanData.mustKeepPlannedOrder(setupDim,reqTrans,setApprovedPlannedOrder))
            {
                reqTrans.CovQty      = 0;
                reqTrans.update(reqPlanData);
            }
            else
            {
                reqTrans.deleteExplosionCoverage(reqPlanData);
                doDelete = true;
            }
        }
        else
            doDelete = true;
Не понятно когда reqPlanData пустым передается