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

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 28.09.2020, 09:33   #1  
oleggy is offline
oleggy
Участник
 
276 / 36 (2) +++
Регистрация: 03.12.2019
Адрес: Россия
DAX09: зависание AX при выборе в AOT меню ПКМ -> Надстройки
Всем привет. Подскажите с чего начать при поиске вот такой проблемы:
Открываю в AOT таблицу и поле (таб. Ledgerjournaltrans поле Due но может быть и другие поля), жму ПКМ -> Надстройки - система зависает на 1 минуту. После меню отображается.
Возможно выполняется какой то запрос?
Просто читал статью: https://axapta.mazzy.ru/lib/querytuning/

Пытался сделать как в статье, но в журнале трассировок операторов SQL не выводится никакой запрос. Возможно это и не запрос даже? Тогда что может быть..
P.S.
Данная проблема проявляется не на всех таблицах и их полях. Только на некоторых.

Последний раз редактировалось oleggy; 28.09.2020 в 09:50.
Старый 28.09.2020, 10:43   #2  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,952 / 3230 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Скорее всего тормозит запро по таблице xref*
Попробуйте перестроить индексы и статистику по всем табличкам xref*

А лучше всего добейтесь чтобы у вас долгие запросы sql логировались и тогда по ним будет ясно.
Старый 28.09.2020, 11:21   #3  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от oleggy Посмотреть сообщение
жму ПКМ -> Надстройки - система зависает на 1 минуту.
она не зависает, а вычитывает практически весь АОТ из псевдо-таблицы UtilElements.
Эта таблица отражает содержимое AOD файлов и содержит всю бизнес-логику.
При последующих выборках, UtilElements будет брать объекты из кэша, поэтому зависаний не заметно.

логика такая - аксапта читает из AOD файлов только те объекты, которые нужны для работы данного клиента. Как правило, это одна-две формы, десяток классов и несколько других объектов. Первое чтение будет немного дольше, но на десятке-другом объектов это не заметно.

при нажатии ПКМ -> Надстройки срабатывает класс SysContextMenu с инструментами разработчика. Этот класс вычитывает почти весь AOT и соответственно тормозит в первый раз.

Примерно такая же бодяга происходит в окне с проектами разработчика при ПКМ -> Создать проект

тут либо полностью переделать SysContextMenu
либо признать, что это торможение - плата за более плавную работу в дальнейшем, и смириться

чтобы смириться, можно придумать другую рационализацию. Например, в JetBrains продуктах с таким количеством объектов вообще невозможно работать, постоянно.

===========
и да, UtilElements - псевдо-таблица, которая не хранится в SQL во всех аксаптах, кроме ax2012.
поэтому запросы к этой таблице невозможно отследить средствами SQL
__________________
полезное на axForum, github, vk, coub.

Последний раз редактировалось mazzy; 28.09.2020 в 11:23.
Старый 07.10.2020, 05:10   #4  
oleggy is offline
oleggy
Участник
 
276 / 36 (2) +++
Регистрация: 03.12.2019
Адрес: Россия
Цитата:
Сообщение от mazzy Посмотреть сообщение
она не зависает, а вычитывает практически весь АОТ из псевдо-таблицы UtilElements.
Эта таблица отражает содержимое AOD файлов и содержит всю бизнес-логику.
При последующих выборках, UtilElements будет брать объекты из кэша, поэтому зависаний не заметно.
Подскажите а если наблюдается такая проблема что зависание происходит постоянно.
Т.е. не только висит 1 минуту, но и при повторной попытке снова висит? По идее должно со второй попытки не должно тормозить.
По таблице Ledgerjournaltrans. Ее размеры:

Что это может быть?

У меня догатка что в коде не происходит сохранения в кэш.
Т.к. после ожидания 1 минуты и выбора какого то пункта в подменю Перекрестные ссылки, выводится как обычно таблица перекрестных ссылок но в добавок выводится infolog - Недопустимый тип контейнера данных.
Если словить его:
[c] \Classes\Info\add 14
[c] \Classes\Global\error 3
[c] \Classes\AfDataContainerDescriptors\createDataContainerDescriptor 69
[c] \Classes\AfDataContainerDescriptors\getDataContainerDescriptor 46
[c] \Classes\AfDataContainer\new 23
[c] \Classes\AfStronglyTypedDataContainer\new 20
[c] \Classes\CustCollectEInvoice_CustTable_NO\new 3


В методе createDataContainerDescriptor - 69:

X++:
private static AfDataContainerDescriptor createDataContainerDescriptor(str _dataContainerType, Map _constructionContext)
{
    str                         methodName;
    SysDictClass                metadataDictClass;
    container                   dataContainerMetadata, dataContainerDescriptorPackage;
    AfDataContainerDescriptor   dataContainerDescriptor;


    // Check if the requested data container descriptor is persisted in the runtime cache
    dataContainerDescriptorPackage = AifRuntimeCacheManager::retrieveEntry(AifRuntimeCacheEntryType::AfDataContainerDescriptors, _dataContainerType);
    if (conlen(dataContainerDescriptorPackage) > 0)
    {
        // Construct the data container descriptor.
        dataContainerDescriptor = AfDataContainerDescriptor::constructFromPackage(dataContainerDescriptorPackage, _constructionContext);
    }
    else
    {
        // Get a dictionary for AfDataContainerDescriptors class.
        metadataDictClass = new SysDictClass(classnum(AfDataContainerDescriptors));

        // Build the name of the method.
        methodName = strfmt('get\%1Metadata', _dataContainerType);

        // Check if the method exists.
        if (metadataDictClass.hasStaticMethod(methodName))
        {
            // The method exists, call it to get the metadata.
            new ExecutePermission().assert();
            // BP deviation documented
            dataContainerMetadata = metadataDictClass.callStatic(methodName, _dataContainerType);
            CodeAccessPermission::revertAssert();
        }
        else
        {
            // The method does not exist, try to get Axd data container metadata.
            dataContainerMetadata = AfDataContainerDescriptors::createAxdDataContainerMetadata(_dataContainerType);
        }

        if (conlen(dataContainerMetadata) > 0)
        {
            // Check the type of the returned metadata
            if (_dataContainerType != conpeek(dataContainerMetadata, #DataContainerTypeIndex))
            {
                // The type of the returned metadata does not match the requested data container type,
                // throw an error.
                throw error("@SYS125458");
            }

            // Construct a data container descriptor from the metadata.
            dataContainerDescriptor = AfDataContainerDescriptor::constructFromMetadata(dataContainerMetadata, _constructionContext);
        }
        else
        {
            // The metadata was not found. Throw an error.
            throw error("@SYS125462"); // <- ошибка тут
        }

        // Persist the data container descriptor in the runtime cache
        AifRuntimeCacheManager::cacheEntry(AifRuntimeCacheEntryType::AfDataContainerDescriptors, _dataContainerType, dataContainerDescriptor.pack());
    }

    return dataContainerDescriptor;
}

Указывает на то что контейнер dataContainerMetadata - пустой.
Я конечно буду смотреть по коду, где данный контейнер должен заполнятся.
Просто вдруг кто сталкивался?
Изображения
 

Последний раз редактировалось oleggy; 07.10.2020 в 06:00.
Старый 11.11.2020, 06:40   #5  
oleggy is offline
oleggy
Участник
 
276 / 36 (2) +++
Регистрация: 03.12.2019
Адрес: Россия
Вроде разобрался из за чего в AX09 постоянно зависает. Дело в том что не происходит сохранение в кэш.

А не происходит из-за того что при обсчете всего AOT наталкивается на такой класс (см. ниже) который пытается инициализировать, генерируется исключение. Выделил данный класс в простой джоб. У всех так?

X++:
static void Job561(Args _args)
{
    CustDocument_CustTable custDocument_CustTable;
    ;

    custDocument_CustTable = new CustDocument_CustTable();
}


Если провалится в new в данном классе видно что тут:

[c] \Classes\AfDataContainerDescriptors\createAxdDataContainerMetadata 19
[c] \Classes\AfDataContainerDescriptors\createDataContainerDescriptor 50
[c] \Classes\AfDataContainerDescriptors\getDataContainerDescriptor 46
[c] \Classes\AfDataContainer\new 23
[c] \Classes\AfStronglyTypedDataContainer\new 20
[c] \Classes\CustDocument_CustTable\new 3
[c] \Classes\AfDataContainerDescriptors\createAxdDataContainerMetadata 19
[c] \Classes\AfDataContainerDescriptors\createDataContainerDescriptor 50
[c] \Classes\AfDataContainerDescriptors\getDataContainerDescriptor 46
[c] \Classes\AfDataContainer\new 23
[c] \Classes\AfStronglyTypedDataContainer\new 20
[c] \Classes\CustDocument_CustTable\new 3


пытается найти класс которого нет в AOT - AxdCustDocument.
Из-за этого и валится.
Я посмотрел, этого класса и не было раньше. Странно.

Создал класс заглушку:

X++:
class AxdCustDocument extends AxdBase
{
}

AifActionInfoList getActionList()
{
    AifActionInfoList ret;

    ret = super();

    return ret;
}

void getConstraintList(Common _curRec, AifConstraintList _constraintList)
{
    super(_curRec, _constraintList);
}

LabelString getLabel()
{
    LabelString ret;

    ret = super();

    return ret;
}


Но теперь валится
Ошибка времени выполнения: QueryBuildDataSource Объект не инициализирован.

(C)\Classes\QueryBuildDataSource\table
(C)\Classes\AfDataContainerDescriptor\createDataItemsFromAxdDataSource - line 38
(C)\Classes\AfDataContainerDescriptor\constructFromMetadata - line 121
(C)\Classes\AfDataContainerDescriptors\createDataContainerDescriptor - line 64
(C)\Classes\AfDataContainerDescriptors\getDataContainerDescriptor - line 46
(C)\Classes\AfDataContainer\new - line 23
(C)\Classes\AfStronglyTypedDataContainer\new - line 20
(C)\Classes\CustDocument_CustTable\new - line 3


Ошибка тут:

X++:
private void createDataItemsFromAxdDataSource(AxdBase _axd, Map _constructionContext)
{
    Query                   axdQuery;
    QueryBuildDataSource    dataSource, childDataSource;
    int                     childDataSourceIndex, childDataSourceCount;
    AxInternalBase          axbc;
    SysDictTable            dictTable;
    Common                  table;
    Set                     tableDataItems;
    Set                     dataSourceDataItems;
    Set                     excludedDataItems;
    str                     documentHashDataItemName;
    int                     nextSerializationOrder = 1;


    // Get Axd query
    axdQuery = _axd.getQuery();

    // Get data source
    dataSource = axdQuery.dataSourceName(this.get_DataSourceName());

    // Create data item descriptors from the data source
    dictTable = new SysDictTable(dataSource.table()); // <-- тут ошибка
    table = dictTable.makeRecord();
    axbc = AxInternalBase::construct(table);
    if (axbc != null)
    ...
}



Причем this.get_DataSourceName() возвращает CustTable, все должно быть корректно.
но dataSource равен null.

Подскажите почему он равен null ?

Последний раз редактировалось oleggy; 11.11.2020 в 08:05.
Старый 11.11.2020, 10:28   #6  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,701 / 1195 (43) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
Как правило, для обслуживающих (сервисных) функций Axapta класс инициализируется только для того, чтобы проверить наличие или отсутствие неких методов или свойств самого класса. Поэтому значение переменных внутри класса в этих случаях не требуется. Вот какие-нибудь "заглушки" там и сделайте на этот случай

Т.е. прямо в методе new() сделайте код обхода, чтобы класс все-таки был инициализирован. Пусть и с явно "кривыми" данными. А "кривизну" проверяйте уже в рабочих методах. Ну, или просто перенесите инициализацию тех объектов, которые создаются в методе new() в первый исполняемый метод класса, чтобы в new() ничего не было

Если же в метод new() у класса передаются какие-то параметры, то можно опираться на тот факт, что в обслуживающих функциях эти параметры никогда не передаются при инициализации класса. Соответственно, делать обход по факту отсутствия переданных параметров

PS: кто там настаивал, что перекрывать метод new() вообще и передавать в него параметры в частности - это хорошо?

Цитата:
Причем this.get_DataSourceName() возвращает CustTable, все должно быть корректно.
но dataSource равен null.

Подскажите почему он равен null ?
Это надо смотреть, а есть ли в запросе, который сформирован в методе _axd.getQuery() источник данных с именем, который возвращает this.get_DataSourceName(). Вполне возможно, что предполагается наличие наследников у основного класса и у этих наследников данные методы перекрыты

В общем, в данном конкретном случае Вы "слишком глубоко копаете". Не надо дальше самого класса CustDocument_CustTable пытаться что-то подправить. Вам надо или обойти инициализацию в самом методе new(), если есть параметры, или перенести весь код из new() в другой метод
__________________
- Может, я как-то неправильно живу?!
- Отчего же? Правильно. Только зря...
Старый 11.11.2020, 14:03   #7  
oleggy is offline
oleggy
Участник
 
276 / 36 (2) +++
Регистрация: 03.12.2019
Адрес: Россия
Цитата:
Сообщение от Владимир Максимов Посмотреть сообщение
Т.е. прямо в методе new() сделайте код обхода, чтобы класс все-таки был инициализирован. Пусть и с явно "кривыми" данными. А "кривизну" проверяйте уже в рабочих методах. Ну, или просто перенесите инициализацию тех объектов, которые создаются в методе new() в первый исполняемый метод класса, чтобы в new() ничего не было

Если же в метод new() у класса передаются какие-то параметры, то можно опираться на тот факт, что в обслуживающих функциях эти параметры никогда не передаются при инициализации класса. Соответственно, делать обход по факту отсутствия переданных параметров
У меня класс new состоит всего из одной строки:
X++:
public void new()
{
    super(#CustDocument_CustTable);
}


Где #define.CustDocument_CustTable('CustDocument.CustTable')

Вообщем я правильно понял что лучше будет в таком случае просто убрать super ?
Просто как быть если возникает предупреждение что в методе не вызывается родительский метод?
Старый 11.11.2020, 17:56   #8  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,701 / 1195 (43) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
Нет. Просто закомментировать нельзя. Вы же сломаете штатную работу с этим классом. Хотя, если они нигде и никак не используется, то, конечно, можно комментировать

Вам надо посмотреть, что там в родительском классе в методе new() происходит. И перенос сделать у родителя. Ну и по всей иерархии, если данный класс - это не один наследник у этого родителя

Цель модификации заключается в том, чтобы, в идеале, в методе new() вообще ничего не было. В крайнем случае, инициализировались бы какие-то константы. Главное, убрать из new() инициализацию других объектов, которые, собственно, и привели к ошибке
__________________
- Может, я как-то неправильно живу?!
- Отчего же? Правильно. Только зря...
 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
dynamicsaxse: May-June 2017 release – Dynamics AX 2012 R3 Blog bot DAX Blogs 0 21.06.2017 00:12
emeadaxsupport: Documentation collection: Inplace upgrade MS Dynamcis AX 2012 RTM --> AX 2012 R2 CU7 Blog bot DAX Blogs 0 22.06.2014 01:19
axsa: MDM Adapter - Extending Dynamics AX 2012 R3 Master Data Management Blog bot DAX Blogs 0 22.05.2014 03:28
axinthefield: Compatibility Testing for Microsoft Dynamics AX Blog bot DAX Blogs 0 23.06.2012 02:26
xplusplus: Dynamics AX Application Object Tree (AOT) Blog bot DAX Blogs 0 25.11.2010 18:11

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

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

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