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

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 24.09.2018, 18:51   #1  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,867 / 3123 (112) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Приведение типов для таблиц ax2012
Всем привет.

Коллеги, ковыряюсь с наследованием табличек.

Возможно ли приводить тип таблички к типу не определенному на этапе компиляции?
Штатный способ
X++:
common as tableName
требует чтобы tableName был именем таблички, т.е. жестко определяется на этапе компиляции. Нельзя поставить переменную.

Сделал вот такой способ
X++:
// приводит табличный буфер к заданному типу
// работает аналогично оператору as
// отличие в том, что 2-м операндом принимает переменную
// т.е. на этапе компиляции тип может быть неизвестен
public static Common as(
    Common          _common,
    TableName       _tableName)
{
    anyType         anyBuffer;
    Common          ret;
    ;

    if (tableName2id(_tableName))
    {
        // anyBuffer = _common as _tableName
        anyBuffer = new SysDictTable(tableName2id(_tableName)).makeRecord();
        anyBuffer = _common;
        ret       = anyBuffer;
    }

    return ret;
}
Работает.
Но он немного хакерский.

Есть что-то более документированное ?
За это сообщение автора поблагодарили: sukhanchik (6).
Старый 24.09.2018, 19:15   #2  
belugin is offline
belugin
Участник
Аватар для belugin
Сотрудники Microsoft Dynamics
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии 2011
Лучший по профессии 2009
 
4,622 / 2922 (107) +++++++++
Регистрация: 16.01.2004
Записей в блоге: 5
Если оно неопределенность на этапе компиляции, то это не привидение типов. В рантайме он уже своего собственного типа. Чего вы хотите добиться?
За это сообщение автора поблагодарили: Logger (1).
Старый 25.09.2018, 11:28   #3  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,867 / 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.
Старый 25.09.2018, 11:36   #4  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,867 / 3123 (112) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Вот еще интересный джоб
X++:
static void reproOrigBug2_MRC(Args _args)
{
    CompanyInfo     companyInfo;
    Common          common5;
    Common          common6;
    
    anytype         anytypeVar;
    ;
    
    common5 = null;
    common6 = null;
    select firstOnly companyInfo;
    
    common5 = companyInfo as DirPartyTable; // здесь отладчик покажет что common5 - тип companyInfo
    anytypeVar = new SysDictTable(tableNum(DirPartyTable)).makeRecord(); // здесь отладчик покажет что anytypeVar - тип DirPartyTable
    anytypeVar = companyInfo; // и здесь anytypeVar - остался с типом DirPartyTable хотя присваивали companyInfo - ну не может проинициализированная переменная anyType сменить тип.
    common6 = anytypeVar; // тоже тип DirPartyTable
}
пояснения в комментариях.

Забыл написать - проверял все на DAX 2012 R3 CU13

Последний раз редактировалось Logger; 25.09.2018 в 11:42.
Старый 25.09.2018, 11:41   #5  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,867 / 3123 (112) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Вообще, все что связано с наследованием таблиц - какое то дырявое.

Вот еще до кучи

http://sysdictcoder.com/inconsistent...ysDictCoder%29

setTmp и иерархические таблицы
Старый 25.09.2018, 13:48   #6  
gl00mie is offline
gl00mie
Участник
MCBMSS
Most Valuable Professional
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,684 / 5788 (200) ++++++++++
Регистрация: 28.11.2005
Адрес: Москва
Записей в блоге: 3
Я в свое время столкнулся с тем, что buffer.TableId для таблиц, использующих наследование, зачастую возвращает идентификатор не совсем той таблицы, к которой относится буфер. Вместо этого обычно возвращается идентификатор одной из родительских таблиц, явно фигурирующих в коде во время компиляции - см. также А что такого принципиального в 2012? По моему хороший разработчик без труда в ней разберется Нужную информацию содержит поле buffer.RelationType, но тут есть нюанс: в интерпретаторе Х++ обращение к этому полю безопасно даже для Common, а вот при генерации CIL это приводит к ошибке компиляции. Более безопасным оказалось вызывать buffer.getInstanceRelationType() - он возвращает название конкретной таблицы-наследника либо пустую строку, если таблица не входит в иерархию наследования. В итоге для определения во время выполнения "настоящего" типа табличного буфера с учетом возможного наследования получился такой вспомогательный метод:
X++:
// возвращает tableId таблицы либо, если таблица поддерживает наследование, то tableId конкретного "наследника"
// safe тут относится к генерации кода CIL, которая валится на простом обращении к Common.RelationType
public static TableId getTableIdOrReltaionTypeSafe(Common _record)
{
    TableNameShort  tableName = _record.getInstanceRelationType();
    TableId         ret = tableName2id(tableName);
    ;
    if (!ret)
    {
        ret = _record.TableId;
    }
    return ret;
}
Полученное значение уже можно использовать, скажем, в new DictTable(tableId).makeRecord()
За это сообщение автора поблагодарили: AlGol (3), raz (10), sukhanchik (8), Logger (8).
Старый 25.09.2018, 16:45   #7  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,867 / 3123 (112) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Цитата:
Сообщение от gl00mie Посмотреть сообщение
...Полученное значение уже можно использовать, скажем, в new DictTable(tableId).makeRecord()
Поправил код с учетом ваших замечаний.

X++:
// обходим баг вызова orig() для табличек с наследованием
// [url=http://axforum.info/forums/showthread.php?p=412642#post412642]Приведение типов для таблиц ax2012[/url]
// [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() буфера
            
            dictTable = new DictTable(tableName2id(_common.getInstanceRelationType()));
            
            if (dictTable)
            {
                // ищем 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;
}
Старый 25.09.2018, 18:01   #8  
pedrozzz is offline
pedrozzz
Молодой, подающий надежды
Аватар для pedrozzz
MCBMSS
Лучший по профессии 2015
 
164 / 218 (8) ++++++
Регистрация: 18.02.2010
Адрес: Краснодар
Цитата:
Сообщение от gl00mie Посмотреть сообщение
Полученное значение уже можно использовать, скажем, в new DictTable(tableId).makeRecord()
есть "стандартный" метод для этого

X++:
SysDictTable::getConcreteTable(record);

X++:
/// <summary>
/// Gets the ID for the concrete table for a specified table.
/// </summary>
/// <param name="_common">
/// The buffer of the given table whose concrete table must be found.
/// </param>
/// <returns>
/// The table ID of the concrete table for the specified table.
/// </returns>
public static TableId getConcreteTable(Common _common)
{
    DictTable dt=new DictTable(_common.TableId);
    TableId concrete=_common.TableId;
    str tablename;
    //Get concrete table for inheritance
    if(dt && dt.supportInheritance())
    {
        tablename= _common.getInstanceRelationType();
        if(tablename)
        {
            concrete=tableName2id(tablename);
        }
    }
    return concrete;
}
__________________
Кононов Пётр

Последний раз редактировалось pedrozzz; 25.09.2018 в 18:12.
За это сообщение автора поблагодарили: sukhanchik (4), Logger (1), gl00mie (3).
Старый 25.09.2018, 16:23   #9  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,867 / 3123 (112) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Ха, а вот такой джоб

X++:
static void reproOrigBug3_MRC(Args _args)
{
    CompanyInfo         companyInfo;
    DirPartyTable       dirPartyTable;
    DirOrganizationBase dirOrganizationBase;

    Common          common5;
    Common          common5_orig;
    Common          common6;
    Common          common6_orig;
    
    anytype         anytypeVar;
    ;

    common5 = null;
    common6 = null;
    
    select firstOnly companyInfo;
    info(strFmt("companyInfo.Name = %1", companyInfo.Name));
    info(strFmt("companyInfo.orig().Name = %1", companyInfo.orig().Name));
    
    dirOrganizationBase = companyInfo as DirOrganizationBase;
    info(strFmt("dirOrganizationBase.Name = %1", dirOrganizationBase.Name));
    info(strFmt("dirOrganizationBase.orig().Name = %1", dirOrganizationBase.orig().Name));
    
    dirPartyTable       = companyInfo as DirPartyTable;
    info(strFmt("dirPartyTable.Name = %1", dirPartyTable.Name));
    info(strFmt("dirPartyTable.orig().Name = %1", dirPartyTable.orig().Name));
    
    common5 = companyInfo as DirPartyTable; // здесь отладчик покажет что common5 - тип companyInfo
    info(strFmt("common5.(fieldNum(dirPartyTable, Name)) = %1", common5.(fieldNum(dirPartyTable, Name))));
    //info(strFmt("common5.orig().(fieldNum(dirPartyTable, Name)) = %1", common5.orig().(fieldNum(dirPartyTable, Name)))); // не компилируется
    common5_orig = common5.orig();
    info(strFmt("common5_orig.(fieldNum(dirPartyTable, Name)) = %1", common5_orig.(fieldNum(dirPartyTable, Name))));
    
    info("");
    info("А так работает (с приведением типа)");
    anytypeVar = new SysDictTable(tableNum(DirPartyTable)).makeRecord(); // здесь отладчик покажет что anytypeVar - тип DirPartyTable
    anytypeVar = companyInfo; // и здесь anytypeVar - остался с типом DirPartyTable хотя присваивали companyInfo - ну не может проинициализированная переменная anyType сменить тип.
    common6 = anytypeVar; // тоже тип DirPartyTable
    
    info(strFmt("common6.(fieldNum(dirPartyTable, Name)) = %1", common6.(fieldNum(dirPartyTable, Name))));
    //info(strFmt("common6.orig().(fieldNum(dirPartyTable, Name)) = %1", common6.orig().(fieldNum(dirPartyTable, Name)))); // не компилируется
    common6_orig = common6.orig();
    info(strFmt("common6_orig.(fieldNum(dirPartyTable, Name)) = %1", common6_orig.(fieldNum(dirPartyTable, Name))));
}
дат такой выхлоп:
Цитата:
companyInfo.Name = Company Dat
companyInfo.orig().Name =
dirOrganizationBase.Name = Company Dat
dirOrganizationBase.orig().Name = icName
dirPartyTable.Name = Company Dat
dirPartyTable.orig().Name = Company Dat
common5.(fieldNum(dirPartyTable, Name)) = Company Dat
common5_orig.(fieldNum(dirPartyTable, Name)) =

А так работает (с приведением типа)
common6.(fieldNum(dirPartyTable, Name)) = Company Dat
common6_orig.(fieldNum(dirPartyTable, Name)) = Company Dat
т.е. если приводить табличный буфер к табличному типу из середины иерархии то просто мусор может в значении придти.

в моем случае в поле companyInfo.name лежит значение "Company Dat"
если начитанный буфер привести к типу dirOrganizationBase то dirOrganizationBase.orig().Name вернет вообще мусор ! Будет возвращено значение "icName" вместо "Company Dat" !!!

Последний раз редактировалось Logger; 25.09.2018 в 16:27.
Старый 25.09.2018, 16:37   #10  
belugin is offline
belugin
Участник
Аватар для belugin
Сотрудники Microsoft Dynamics
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии 2011
Лучший по профессии 2009
 
4,622 / 2922 (107) +++++++++
Регистрация: 16.01.2004
Записей в блоге: 5
Тут может быть проблема в том, что Common ведет себя иногда как ссылочный тип, иногда как значение.
Старый 25.09.2018, 16:55   #11  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,867 / 3123 (112) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Цитата:
Сообщение от belugin Посмотреть сообщение
Тут может быть проблема в том, что Common ведет себя иногда как ссылочный тип, иногда как значение.
Похоже, что табличный тип это не совсем тип, а некий интерфейс.
И получается в иерархии DirPartyTable ... CompanyInfo у нас есть набор интерфейсов по работе с ядреным курсором.

При этом реализация DirPartyTable.orig() и CompanyInfo.orig() разная. Каждый знает только про свой набор полей - про тот набор, который мы в AOT для таблички описали. И именно этот набор полей при вызове и заполняет в возвращаемом буфере.

Соответственно, задача стояла как получить доступ к соответствующему интерфейсу курсора. Если в коде объявлена переменная соответствующего типа, то все просто, а если ее нет, то как ее получить в runTime.
Ну, я нашел способ.

P.S.
Кстати, аналогичная проблема возникает при помещении и извлечении буфера в List (см. http://sashanazarov.blogspot.com/201...n-objects.html)

а также при помещении и извлечении в контейнер таким способом, популярным в предыдущих версиях:
X++:
con = [buffer];
buffer = conPeek(con, 1);
там тоже при использовании наследуемых табличек теряется инфа о других полях (не из текущего типа).

Видимо, во всех этих случаях задействован какой-то общий механизм в ядре.
Старый 28.09.2018, 11:18   #12  
gl00mie is offline
gl00mie
Участник
MCBMSS
Most Valuable Professional
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,684 / 5788 (200) ++++++++++
Регистрация: 28.11.2005
Адрес: Москва
Записей в блоге: 3
Я хотел было побрюзжать, что стандартный метод всегда создает экземпляр DictTable, но вспомнил тут одну особенность ядра: я некогда его ковырял (интересно же) и обнаружил, что экземпляры Dict-классов не каждый раз создаются и удаляются по мере работы кода X++, а создаются один раз при загрузке, затем ссылки на их эксземпляры сохраняются в массиве указателей, где индексом является идентификатор соотв. объекта. Возможно, для объектов приложения используется ленивая инициализация Dict-классов, но для объектов ядра (классов и таблиц) инициализация массива указателей происходит при загрузке ядра.
Таким образом, new DictTable() или new DictClass() транслируется ядром в обращение к массиву указателей и в общем случае отрабатывает очень быстро, без выделения памяти и последующей работы сборщика мусора. Поэтому Dict-классы - это очень быстрый API отражения, в отличие, скажем, от TreeNode. Что примечательно, SysDict-классы такой особенностью, насколько я знаю, не обладают и создаются, как любые другие объекты Х++, так что с точки зрения производительности с SysDict-классами стоит быть осторожнее.
За это сообщение автора поблагодарили: sukhanchik (4), pedrozzz (3), skuull (2).
Старый 28.09.2018, 12:39   #13  
Raven Melancholic is offline
Raven Melancholic
Участник
Аватар для Raven Melancholic
Самостоятельные клиенты AX
Лучший по профессии 2015
 
2,158 / 1286 (47) ++++++++
Регистрация: 21.03.2005
Адрес: Москва-Петушки
Цитата:
Сообщение от gl00mie Посмотреть сообщение
Что примечательно, SysDict-классы такой особенностью, насколько я знаю, не обладают и создаются, как любые другие объекты Х++, так что с точки зрения производительности с SysDict-классами стоит быть осторожнее.
То есть, если правильно понимаю, лучше не создавать SysDict*, а Dict* и потом приводить к SysDict*, если нужны методы именно Sys?
За это сообщение автора поблагодарили: Logger (1).
Старый 28.09.2018, 11:37   #14  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,867 / 3123 (112) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Вот откуда растут ноги у такого агрессивного кеширования всего на свете в 2012-й...
Старый 01.03.2020, 19:55   #15  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,867 / 3123 (112) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Ха!
Оказывается методы isSql() и Name(dbBackend::Sql) класса DictIndex возвращают неправильное значение для для табличек из иерархии наследования.
isSql() - всегда false
Name(dbBackend::Sql) - всегда ''

Да что же это такое! Почему реализация работы с наследованием в ядре такая кривая ?
Старый 01.03.2020, 20:03   #16  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,867 / 3123 (112) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Фикс с исправлением для SysDictIndex во вложении.
Вложения
Тип файла: zip FixDictIndex.zip (30.0 Кб, 139 просмотров)
Теги
inheritance, table inheritance, type cast

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
[AX2012] Наследование таблиц. iCloud DAX: Программирование 4 26.03.2014 15:28
AX2012 - изменение связи таблиц на форме DTD DAX: Программирование 4 10.12.2013 16:30
Как сравнить financials dimensions у двух таблиц (AX2012) ? DTD DAX: Программирование 0 17.07.2013 15:16
AX2012: drag'n'drop и поля таблиц wojzeh DAX: Программирование 2 18.01.2012 22:07
приведение типов в select simply2double DAX: Программирование 3 30.09.2004 11:24
Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра
Комбинированный вид Комбинированный вид

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

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

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 23:08.
Powered by vBulletin® v3.8.5. Перевод: zCarot
Контактная информация, Реклама.