Показать сообщение отдельно
Старый 25.09.2006, 13:20   #5  
Gustav is offline
Gustav
Moderator
Аватар для Gustav
SAP
Лучший по профессии 2009
 
1,858 / 1152 (42) ++++++++
Регистрация: 24.01.2006
Адрес: Санкт-Петербург
Записей в блоге: 19
:( Грабля на пути универсального запроса к любой таблице
Добрый день, уважаемые коллеги,

Тестируя некую процедуру, получил аналогичную ошибку.

Процедура моя делает следующее (ни много, ни мало):
- пробегает в цикле по списку всех таблиц Axapta;
- для "живых" таблиц, т.е. существующих в БД и содержащих хотя бы одну запись, создает динамический запрос, который запускается на выполнение;
- "внутри запроса" пробегаются все поля самой первой записи и присваивается их значение некоторой anytype-переменной. Само значение этой переменной сейчас не суть важно - тестируется именно корректность присваивания;
- по окончании работы в инфологе отображается список живых таблиц (id и name).

Вот работающая версия (job 1), которая всё это нормально делает. Время работы джоба зависит от конкретного кол-ва живых таблиц в вашей Аксапте (у меня их около 450 и время выполнения - около минуты).
X++:
static void KKu_Job_6923_RunQuery_1(Args _args)
{
    Dictionary  dictionary = new Dictionary();
    TableId     tableId;
    DictTable   dictTable;
    int         i;
     
    int         timeFullStart, timeFullFinish, timeFullTotal;
     
    Common                  common;
     
    Query                   query;
    QueryBuildDataSource    qbds;
    QueryBuildFieldList     qbfl;
     
    QueryRun                qr;
     
    FieldId                 fieldId;
    DictField               dictField;
     
    int                     row;
    int                     j, k;
    anytype                 val;
    ;
     
    timeFullStart = timenow();
     
    // цикл по таблицам
    for (i=1; i<= dictionary.tableCnt(); i++)
    {
        tableId   = dictionary.tableCnt2Id(i);
        dictTable = new DictTable(tableId);
     
// момент A
     
        // если в очередной таблице нет записей,
        // то переходим к следующей
        if (!(new SysDictTable(tableId).recordCount()))
            continue;
     
        info(strfmt('%1 == %2' , tableId, dictTable.name()));
     
        query = new Query ();
     
        qbds = query.AddDataSource(tableId);
        qbfl = qbds.fields();
     
        qr = new QueryRun (query);
     
        row = 0;
        while (qr.next())
        {
            row++;
            if (row > 1) break;
     
            // получаем запись
            common = qr.get(tableId);
     
            // цикл по полям таблицы (запроса)
            for(j=1; j<= qbfl.fieldCount(); j++)
            {
                fieldId = qbfl.field(j);
                dictField = new DictField(tableId, fieldId);
     
                // если поле не SQL, то переходим к следующему полю
                if (!dictField.isSql())
                    continue;
     
                // цикл по элементам массива поля
                for(k=1; k<= dictField.arraySize(); k++)
                {
                    val = common.(fieldId2Ext(fieldId, k));
                }
            }
        }
     
// момент B
     
    }
     
    timeFullFinish = timenow();
    timeFullTotal = timeFullFinish - timeFullStart;
    info(strfmt('Время выполнения: %1 сек', timeFullTotal));
}
Но мне надо, чтобы фрагмент от "момента A" до "момента B" (см. в коде выше) был оформлен в виде отдельного метода, в который в качестве параметра будет передаваться DictTable-переменная.
Создаем второй джоб, где всё это имитируется. Забегая вперед, отмечу что в классе, откуда выдран этот фрагмент у меня происходит то же самое, что и в job 2.
X++:
static void KKu_Job_6923_RunQuery_2(Args _args)
{
    Dictionary  m_dictionary;
    TableId     m_tableId;
    DictTable   m_dictTable;
    int         i;
     
    void processTable(DictTable _dictTable)
    {
        Common                  common;
     
        Query                   query;
        QueryBuildDataSource    qbds;
        QueryBuildFieldList     qbfl;
     
        QueryRun                qr;
     
        TableId                 tableId;
     
        FieldId                 fieldId;
        DictField               dictField;
     
        int                     row;
        int                     j, k;
        anytype                 val;
        ;
     
        tableId = _dictTable.id();
     
        // если в очередной таблице нет записей,
        // то переходим к следующей
        if (!(new SysDictTable(tableId).recordCount()))
            return;
     
        info(strfmt('========== %1 == %2 ==========' , tableId, _dictTable.name()));
     
        query = new Query ();
     
        qbds = query.AddDataSource(tableId);
        qbfl = qbds.fields();
     
        qr = new QueryRun (query);
     
        row = 0;
        while (qr.next())
        {
            row++;
            if (row > 1) break;
     
            // получаем запись
            common = qr.get(tableId);
     
            // цикл по полям таблицы (запроса)
            for(j=1; j<= qbfl.fieldCount(); j++)
            {
                fieldId = qbfl.field(j);
                dictField = new DictField(tableId, fieldId);
     
                // если поле не SQL, то переходим к следующему полю
                if (!dictField.isSql())
                    continue;
     
                // цикл по элементам массива поля
                for(k=1; k<= dictField.arraySize(); k++)
                {
                    info(strfmt('   -- %1 -- %2 -- %3 -- %4',
                                tableId, _dictTable.name(),
                                fieldId, dictField.name()));
     
                    val = common.(fieldId2Ext(fieldId, k));
     
                    info(strfmt('      val = %1' , val));
                }
            }
        }
    }
     
//====================================================================
     
    m_dictionary = new Dictionary();
     
    // цикл по таблицам
    for (i=1; i<= m_dictionary.tableCnt(); i++)
    {
        m_tableId   = m_dictionary.tableCnt2Id(i);
        m_dictTable = new DictTable(m_tableId);
     
        // if (m_tableId == 8) continue;
        // if (m_tableId == 24) continue;
     
        processTable(m_dictTable);
    }
}
Джоб 2 работает через "пень-колоду", т.е. на каких-то таблицах всё проходит гладко, а на других вылетает. Я делал так: по мере отлова очередной "плохой" таблицы, на которой джоб валился, включал в цикл по таблицам "пропуск" этой таблицы в виде оператора: if (m_tableId == 8) continue; Очередную свалившуюся таблицу и поле, на котором это произошло, можно наблюдать в самой последней строке инфолога.

Итак, вопрос мой, думаю, понятен. Что же это такое и как бы это победить?
Заранее благодарю всех откликнувшихся.

P.S. Параметр метода processTable(DictTable _dictTable) я уже менял и так, и сяк: и tableId передавал как int, и tableName как str (с соответствующими модификациями внутренностей метода) - результат один и тот же и пока неудовлетворительный...

Еще заметил, что если подставить в оператор val = common.(fieldId2Ext(fieldId, k)) литеральную константу, соответствующую сбойному fieldId, то всё опять работает! Что же это за фигня такая... Ощущение такое, что "гадость" тянется в метод через параметр и всё, что с ним так или иначе связано внутри, несёт на себе этот "гадкий" след...
Миниатюры
Нажмите на изображение для увеличения
Название: error_25_2.jpg
Просмотров: 437
Размер:	16.6 Кб
ID:	2110  
Изображения
 
За это сообщение автора поблагодарили: Poleax (1).