Добрый день, уважаемые коллеги,
Тестируя некую процедуру, получил аналогичную ошибку.
Процедура моя делает следующее (ни много, ни мало):
- пробегает в цикле по списку всех таблиц 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, то всё опять работает! Что же это за фигня такая... Ощущение такое, что "гадость" тянется в метод через параметр и всё, что с ним так или иначе связано внутри, несёт на себе этот "гадкий" след...