|
|
#1 |
|
Участник
|
Приведение типов для таблиц ax2012
Всем привет.
Коллеги, ковыряюсь с наследованием табличек. Возможно ли приводить тип таблички к типу не определенному на этапе компиляции? Штатный способ X++: common as 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). | |
|
|
#2 |
|
Участник
|
Если оно неопределенность на этапе компиляции, то это не привидение типов. В рантайме он уже своего собственного типа. Чего вы хотите добиться?
|
|
|
|
| За это сообщение автора поблагодарили: Logger (1). | |
|
|
#3 |
|
Участник
|
Цитата:
Изначально я пытался порешать вот эту проблему: 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. |
|
|
|
|
#4 |
|
Участник
|
Вот еще интересный джоб
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. |
|
|
|
|
#5 |
|
Участник
|
Вообще, все что связано с наследованием таблиц - какое то дырявое.
Вот еще до кучи http://sysdictcoder.com/inconsistent...ysDictCoder%29 setTmp и иерархические таблицы |
|
|
|
|
#6 |
|
Участник
|
Я в свое время столкнулся с тем, что 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; } |
|
|
|
| За это сообщение автора поблагодарили: AlGol (3), raz (10), sukhanchik (8), Logger (8). | |
|
|
#7 |
|
Участник
|
Ха, а вот такой джоб
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. |
|
|
|
|
#8 |
|
Участник
|
Тут может быть проблема в том, что Common ведет себя иногда как ссылочный тип, иногда как значение.
|
|
|
|
|
#9 |
|
Участник
|
Цитата:
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; } |
|
|
|
|
#10 |
|
Участник
|
Цитата:
И получается в иерархии 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); Видимо, во всех этих случаях задействован какой-то общий механизм в ядре. |
|
|
|
|
#11 |
|
Молодой, подающий надежды
|
Цитата:
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). | |
|
|
#12 |
|
Участник
|
Я хотел было побрюзжать, что стандартный метод всегда создает экземпляр DictTable, но вспомнил тут одну особенность ядра: я некогда его ковырял (интересно же) и обнаружил, что экземпляры Dict-классов не каждый раз создаются и удаляются по мере работы кода X++, а создаются один раз при загрузке, затем ссылки на их эксземпляры сохраняются в массиве указателей, где индексом является идентификатор соотв. объекта. Возможно, для объектов приложения используется ленивая инициализация Dict-классов, но для объектов ядра (классов и таблиц) инициализация массива указателей происходит при загрузке ядра.
Таким образом, new DictTable() или new DictClass() транслируется ядром в обращение к массиву указателей и в общем случае отрабатывает очень быстро, без выделения памяти и последующей работы сборщика мусора. Поэтому Dict-классы - это очень быстрый API отражения, в отличие, скажем, от TreeNode. Что примечательно, SysDict-классы такой особенностью, насколько я знаю, не обладают и создаются, как любые другие объекты Х++, так что с точки зрения производительности с SysDict-классами стоит быть осторожнее. |
|
|
|
| За это сообщение автора поблагодарили: sukhanchik (4), pedrozzz (3), skuull (2). | |
|
|
#13 |
|
Участник
|
Вот откуда растут ноги у такого агрессивного кеширования всего на свете в 2012-й...
|
|
|
|
|
#14 |
|
Участник
|
То есть, если правильно понимаю, лучше не создавать SysDict*, а Dict* и потом приводить к SysDict*, если нужны методы именно Sys?
|
|
|
|
| За это сообщение автора поблагодарили: Logger (1). | |
|
|
#15 |
|
Участник
|
Ха!
Оказывается методы isSql() и Name(dbBackend::Sql) класса DictIndex возвращают неправильное значение для для табличек из иерархии наследования. isSql() - всегда false Name(dbBackend::Sql) - всегда '' Да что же это такое! Почему реализация работы с наследованием в ядре такая кривая ? |
|
|
|
|
#16 |
|
Участник
|
Фикс с исправлением для SysDictIndex во вложении.
|
|
|
|
|
#17 |
|
NavAx
|
Я тут немного поковырял свой обход с невыборкой полей таблицы-предка в orig() таблицы - потомка и сделал проще.
Перечислять поля и писать методы - это долго. ![]() Проще скопировать значения недостающих полей (на примере договоров с клиентами): Мне нужно было его получить правильный orig() в методе таблицы SalesAgreementHeaderExt_RU.update(): X++: AgreementHeaderExt_RU baseOrig = this as AgreementHeaderExt_RU;
SalesAgreementHeaderExt_RU this_orig = this.orig();
baseOrig = baseOrig.orig();
buf2Buf(baseOrig, this_orig);Если уровней наследования будет больше - buf2buf нужно сделать несколько раз.
__________________
Жизнь прекрасна! Если, конечно, правильно подобрать антидепрессанты...
|
|
|
|
| За это сообщение автора поблагодарили: Logger (5). | |
|
|
#18 |
|
Участник
|
Цитата:
т.е. orig() базовой таблички в иерархии наследования все поля заполняет. Будем знать. А в CIL проверяли ? Лучше проверить. Бывают отличия в поведении. |
|
|
|
|
#19 |
|
Участник
|
Цитата:
Я для комфорта завел несколько вспомогательных методов на SysDictTable as_ByFieldId и as_ByFieldName Их попроще использовать С учетом их метод глобала стал таким 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] // DevRecordInfo_FixRetrieve "Исправление ошибок "Поле "XXX" в таблице "YYY" не было явным образом выбрано.", "Аргумент метода isF", PKoz 15.08.2024 public static anytype origFieldValue_MRC(Common _common, FieldId _fieldId) { Common commonCasted; Common commonOrig; 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 { commonCasted = SysDictTable::as_ByFieldId(_common, _fieldId); commonOrig = commonCasted.orig(); ret = commonOrig.(_fieldId); } return ret; } Там вообще, все печальнее, так как багу подвержен не только orig но и другие методы. Цитирую коммент из кода для as_ByFieldId X++: // приводит табличный буфер к заданному типу // работает аналогично оператору as // отличие в том, что 2-м операндом принимает идентификатор поля // т.е. на этапе компиляции тип может быть неизвестен // актуально для табличек с наследованием // так как для них бывает важно получить буфер с табличным типом таким, для // которого как раз определено поле с идентификатором _fieldId // это важно так как из-за кривого ядра в 2012-й аксапте некоторые методы ядра // для табличек с наследованием корректно работают только если вызваны на // переменной с таким типом // Пример // xRecord.orig() // xRecord.isFieldDataRetrieved() // и.т.п. // похоже, в ядре забыли в реализации подобных методов учесть, что появилось // наследование и если на типе табличного буфера не определено поле _fieldId (но // определено на каком-то из родителей) то указанные методы работали неправильно // или даже выбрасывали исключение // поэтому чтобы обойти эти проблемы перед вызовом таких методов сперва приводим // табличный буфер к нужному типу, например, вызываем // не common.isFieldDataRetrieved(fieldName) // а SysDictTable::as_ByFieldId(common, fieldName2Id(common.TableId, fieldName)).isFieldDataRetrieved(fieldName) |
|
|
|
|
#20 |
|
Участник
|
А вот сами методы класса SysDictTable
X++: // см. \Classes\SysDictTable\as_ByFieldId // DevRecordInfo_FixRetrieve "Исправление ошибок "Поле "XXX" в таблице "YYY" не было явным образом выбрано.", "Аргумент метода isF", PKoz 15.08.2024 public static TableId getConcreteTableIdByFieldId_MRC(Common _common, FieldId _fieldId) { DictTable dictTable; TableId tableId; TableId tableId4Field; str fieldName; ; dictTable = new DictTable(_common.TableId); if (!(dictTable && dictTable.supportInheritance())) { return _common.TableId; } // Get concrete table for inheritance dictTable = new DictTable(tableName2id(_common.getInstanceRelationType())); if (dictTable) { // ищем tableId в иерархии наследования для которой первой определено поле _fieldId т.е. ту для которой оно было введено, а не отнаследовано. // fieldName = fieldId2name(_common.TableId, _fieldId); fieldName = fieldId2name(dictTable.id(), _fieldId); // в CIL для таблиц с наследованием лучше использовать не _common.TableId а tableName2id(_common.getInstanceRelationType()) // а еще лучше SysDictTable::getConcreteTable() так как он работает для любых табличек // метод getInstanceRelationType() для ненаследуемых табличек выдает пустую строку но в нашем случае можно его юзать так как заведомо наследование есть в этом месте, // а работать будет быстрее чем SysDictTable::getConcreteTable() // см. [url=http://axforum.info/forums/showthread.php?p=412646#post412646]Приведение типов для таблиц ax2012[/url] // tableId4Field = _common.TableId; tableId4Field = dictTable.id(); if (fieldName) { tableId = dictTable.extends(); while (tableId) { dictTable = new DictTable(tableId); if (fieldName2id(tableId, fieldName)) { tableId4Field = tableId; } else { break; } tableId = dictTable.extends(); } } } if (!tableId4Field) { // не должны сюда попасть. Можно кидать исключение. throw error(strFmt("Не получилось определить таблицу для буфера %1, RecId = %2, поле = %3 (id поля = %4)", tableId2name(SysDictTable::getConcreteTable(_common)), _common.RecId, fieldId2name(_common.TableId, _fieldId), _fieldId )); } return tableId4Field; } X++: // см. \Classes\SysDictTable\as_ByFieldName // DevRecordInfo_FixRetrieve "Исправление ошибок "Поле "XXX" в таблице "YYY" не было явным образом выбрано.", "Аргумент метода isF", PKoz 15.08.2024 public static TableId getConcreteTableIdByFieldName_MRC(Common _common, FieldName _fieldName) { TableId tableId; FieldId fieldId; TableId ret; ; // fieldId = fieldName2id(_common.TableId, _fieldName); tableId = SysDictTable::getConcreteTable(_common); fieldId = fieldName2Id(tableId, _fieldName); ret = SysDictTable::getConcreteTableIdByFieldId_MRC(_common, fieldId); return ret; } X++: // [url=https://axforum.info/forums/showthread.php?t=78933]Приведение типов для таблиц ax2012[/url] // DevRecordInfo_FixRetrieve "Исправление ошибок "Поле "XXX" в таблице "YYY" не было явным образом выбрано.", "Аргумент метода isF", PKoz 15.08.2024 public static Common as_ByFieldId( Common _common, FieldId _fieldId ) { anytype anyBuffer; TableId tableId; Common ret; ; if (_fieldId) { tableId = SysDictTable::getConcreteTableIdByFieldId_MRC(_common, _fieldId); if (tableId) { // anyBuffer = _common as tableId2Name(tableId); anyBuffer = new DictTable(tableId).makeRecord(); anyBuffer = _common; ret = anyBuffer; } } return ret; } X++: // [url=https://axforum.info/forums/showthread.php?t=78933]Приведение типов для таблиц ax2012[/url] // DevRecordInfo_FixRetrieve "Исправление ошибок "Поле "XXX" в таблице "YYY" не было явным образом выбрано.", "Аргумент метода isF", PKoz 15.08.2024 public static Common as_ByFieldName( Common _common, FieldName _fieldName ) { anytype anyBuffer; TableId tableId; Common ret; ; if (_fieldName) { tableId = SysDictTable::getConcreteTableIdByFieldName_MRC(_common, _fieldName); if (tableId) { // anyBuffer = _common as tableId2Name(tableId); anyBuffer = new DictTable(tableId).makeRecord(); anyBuffer = _common; ret = anyBuffer; } } return ret; } |
|
|
| Теги |
| inheritance, isfielddataretrieved, orig, table inheritance, type cast |
|
|
|