Показать сообщение отдельно
Старый 25.09.2018, 11:28   #3  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,873 / 3123 (112) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Цитата:
Сообщение от belugin Посмотреть сообщение
Если оно неопределенность на этапе компиляции, то это не привидение типов. В рантайме он уже своего собственного типа. Чего вы хотите добиться?
Как бы да, но не совсем. По крайней мере для переменных табличного типа в аксапте это не совсем так. Видимо мы имеем пример "дырявой абстракции" когда табличные переменные должны вести себя как классы, но так не происходит в реальности.

Изначально я пытался порешать вот эту проблему:
http://sashanazarov.blogspot.com/201...-fails-on.html

Для решения написал метод в Global (он как раз решает проблему описанную в блоге sashanazarov - позволяет обойти баги ядра)
X++:
// обходим баг вызова orig() для табличек с наследованием
// [url]http://sashanazarov.blogspot.com/2014/01/dynamics-ax-2012-orig-method-fails-on.html[/url]
// [url=http://axforum.info/forums/showthread.php?p=328140#post328140]Опасный orig[/url]    
public static anyType origFieldValue_MRC(Common _common, FieldId _fieldId)
{
    TableId     tableId;
    TableId     tableId4Field;
    FieldName   fieldName;
    
    Common      commonCasted;
    Common      commonOrig;
    
    DictTable   dictTable;
    
    anytype     ret;
    ;

    if (_common.RecId == 0)
    {   // обходим баг
        // [url=http://axforum.info/forums/showthread.php?p=328140#post328140]Опасный orig[/url]
        commonOrig = _common.orig();
        commonOrig.doClear();
        ret = commonOrig.(_fieldId);
    }
    else
    {   
        dictTable = new DictTable(_common.TableId);
        
        if (!(dictTable && dictTable.supportInheritance()))
        {   // обычная табличка без наследования - все как обычно
            commonOrig = _common.orig();
            ret = commonOrig.(_fieldId);
        }
        else
        {   // обходим баг
            // [url]http://sashanazarov.blogspot.com/2014/01/dynamics-ax-2012-orig-method-fails-on.html[/url]
            // решаем проблемы с получением значений из родительских табличек для orig() буфера
            
            // ищем tableId в иерархии наследования для которой первой определено поле _fieldId т.е. ту для которой оно было введено, а не отнаследовано.
            fieldName = fieldId2name(_common.TableId, _fieldId);
            tableId4Field = _common.TableId;
            
            if(fieldName)
            {
                tableId = dictTable.extends();
                
                while(tableId)
                {
                    dictTable = new DictTable(tableId);
                    
                    if (fieldName2id(tableId, fieldName))
                    {
                        tableId4Field = tableId;
                    }
                    else
                    {
                        break;
                    }
                    
                    tableId = dictTable.extends();
                }
            }
            
            if (tableId4Field)
            {
                commonCasted = SysDictTable::as(_common, tableId2name(tableId4Field));
                commonOrig = commonCasted.orig();
                ret = commonOrig.(_fieldId);
            }
            else
            {
                // не должны сюда попасть. Можно кидать исключение.
                commonOrig = _common.orig();
                ret = commonOrig.(_fieldId);                
            }
        }
    }

    return ret;
}

иллюстрация работы метода origFieldValue_MRC - джоб:
X++:
// [url]http://sashanazarov.blogspot.com/2014/01/dynamics-ax-2012-orig-method-fails-on.html[/url]
static void reproOrigBug_MRC(Args _args)
{
    CompanyInfo     companyInfo;
    DirPartyTable   dirPartyTable;
    
    Common          common5;
    Common          common6;
    
    anytype         any;
    ;
    
    select firstOnly companyInfo;
    
    info(strFmt("Поле СompanyInfo.DataAreaId (системное. Определено на СompanyInfo). Значение \"%1\"", companyInfo.DataAreaId));
    info(strFmt("Поле СompanyInfo.VATNum (не наследовано). Значение \"%1\"", companyInfo.VATNum));
    info(strFmt("Поле СompanyInfo.Name (наследовано из DirPartyTable - от головной таблички в иерархии наследования). Значение \"%1\"", companyInfo.Name));
    info(strFmt("Поле СompanyInfo.PhoneticName (наследовано из DirOrganizationBase - от промежуточной таблички в иерархии наследования. 1-й уровень наследования). Значение \"%1\"", companyInfo.PhoneticName));
    info(strFmt("Поле СompanyInfo.DEL_RelationTypeName_OMInternalOrg (наследовано из OMInternalOrganization - от промежуточной таблички в иерархии наследования. 2-й уровень наследования). Значение \"%1\"", companyInfo.DEL_RelationTypeName_OMInternalOrg));
    info("");
    info("Теперь проверяем работу Orig()");
    info("");
    info("1. Обычный вызов companyInfo.orig().FieldName - для полей из таблиц родителей - теряем значения");
    info(strFmt("companyInfo.orig().DataAreaId = \"%1\"", companyInfo.orig().DataAreaId)); 
    info(strFmt("companyInfo.orig().VATNum = \"%1\"", companyInfo.orig().VATNum));
    info(strFmt("companyInfo.orig().Name = \"%1\"     %2", companyInfo.orig().Name, (companyInfo.orig().Name ? "" : "Потеряли значение !")));
    info(strFmt("companyInfo.orig().PhoneticName = \"%1\"      %2", companyInfo.orig().PhoneticName, (companyInfo.orig().PhoneticName ? "" : "Потеряли значение !")));
    info(strFmt("companyInfo.orig().DEL_RelationTypeName_OMInternalOrg = \"%1\"     %2", companyInfo.orig().DEL_RelationTypeName_OMInternalOrg, (companyInfo.orig().DEL_RelationTypeName_OMInternalOrg ? "" : "Потеряли значение !")));
    info("");

    dirPartyTable = companyInfo as DirPartyTable;
    info("2. Явно приводим тип к табличной переменной другого типа. dirPartyTable = companyInfo as DirPartyTable. Вызов dirPartyTable.orig().FieldName.  Лечит проблему но неудобно использовать. Надо помнить из какой таблички пришло поле в иерархии наследования. Держать в коде отдельную табличную переменную другого типа.");
    info(strFmt("dirPartyTable.orig().DataAreaId = \"%1\"", dirPartyTable.orig().DataAreaId));
    info(strFmt("dirPartyTable.orig().VATNum - НЕПРИМЕНИМО" /*, dirPartyTable.orig().VATNum*/));
    info(strFmt("dirPartyTable.orig().Name = \"%1\"", dirPartyTable.orig().Name));
    info(strFmt("dirPartyTable.orig().PhoneticName - НЕПРИМЕНИМО" /*, dirPartyTable.orig().PhoneticName*/));
    info(strFmt("dirPartyTable.orig().DEL_RelationTypeName_OMInternalOrg - НЕПРИМЕНИМО" /*, dirPartyTable.orig().DEL_RelationTypeName_OMInternalOrg*/));
    info("");
    
    
    info("3. Попытка достать через common.orig() и прочие танцы с бубном - не помогло");
    common5 = null;
    common6 = null;
    
    common5 = new SysDictTable(tableNum(DirPartyTable)).makeRecord(); // тип DirPartyTable
    common5.data(companyInfo); // тип DirPartyTable , но это не помогает вытащить правильное значение
    common6 = common5.orig(); // тип DirPartyTable , но это не помогает вытащить правильное значение
    info(strFmt("common6.(fieldNum(DirPartyTable, Name)) = \"%1\"", common6.(fieldNum(DirPartyTable, Name))));
    
    common5 = null;
    common6 = null;
    common5 = new SysDictTable(tableNum(DirPartyTable)).makeRecord();  // тип DirPartyTable , но это не помогает вытащить правильное значение
    common5.data(companyInfo.orig()); // вот тут уже при вызове Orig() значение потеряно
    common6 = common5;
    info(strFmt("common6.(fieldNum(DirPartyTable, Name)) = \"%1\"", common6.(fieldNum(DirPartyTable, Name))));
    info("");
    
    info("4. Игры с приведением типов через переменную с типом anyType - все хорошо, но неудобно использовать.");
    any = new SysDictTable(tableNum(DirPartyTable)).makeRecord(); // any - тип DirPartyTable
    any = companyInfo;  // any - все равно тип DirPartyTable - в этот момент происходит "приведение" типа.
    common5 = any; // common5 - тип DirPartyTable
    common6 = common5.orig(); // common6 - тип DirPartyTable
    info(strFmt("common6.(fieldNum(DirPartyTable, Name)) = \"%1\"", common6.(fieldNum(DirPartyTable, Name))));
    info("");

    info("5. Достаем значение вызовом origFieldValue_MRC(companyInfo, ...) - все нормально. Удобно использовать.");
    info(strFmt("origFieldValue_MRC(companyInfo, fieldnum(CompanyInfo, DataAreaId)) = \"%1\"", origFieldValue_MRC(companyInfo, fieldnum(CompanyInfo, DataAreaId)))); 
    info(strFmt("origFieldValue_MRC(companyInfo, fieldnum(CompanyInfo, VATNum)) = \"%1\"", origFieldValue_MRC(companyInfo, fieldnum(CompanyInfo, VATNum)))); 
    info(strFmt("origFieldValue_MRC(companyInfo, fieldnum(CompanyInfo, Name)) = \"%1\"", origFieldValue_MRC(companyInfo, fieldnum(CompanyInfo, Name)))); 
    info(strFmt("origFieldValue_MRC(companyInfo, fieldnum(CompanyInfo, PhoneticName)) = \"%1\"", origFieldValue_MRC(companyInfo, fieldnum(CompanyInfo, PhoneticName)))); 
    info(strFmt("origFieldValue_MRC(companyInfo, fieldnum(CompanyInfo, DEL_RelationTypeName_OMInternalOrg)) = \"%1\"", origFieldValue_MRC(companyInfo, fieldnum(CompanyInfo, DEL_RelationTypeName_OMInternalOrg)))); 
    info("");
}

Последний раз редактировалось Logger; 25.09.2018 в 11:38.