Работа с Record. Часть четвертая, практическая
Предыдущие части можно найти здесь: «1. Основные команды. Чтение данных без блокировок», «2. Modify», «3. FILTERGROUP. Другие фирмы».
Примеры из практики Navision
Вам необходимо получить остатки определенного товара на определенном складе. Есть два способа сделать это. У обоих способов есть свои за и против.
- ПРАВИЛЬНО — (ЗА — вам не нужно заботиться об индексах. ПРОТИВ — задействование обычных полей для присвоения значений и наложение фильтров на FLOWFILTER’ы).
CLEAR(recItem);
recItem."No." := '1000'; // или recItem.GET('1000');
recItem.SETRANGE("Location Filter",'BLU');
recItem.CALCFIELDS(Inventory);
MESSAGE('%1',recItem.Inventory); - ПРАВИЛЬНО (ЗА — нет присвоения значения и всегда используются фильтры, ПРОТИВ — необходимо знать конкретный индекс, используемый для получения значения вычисляемого SIFT-поля):
recItemLedgerEntry.RESET;
recItemLedgerEntry.SETCURRENTKEY("Item no.","Location Code");
recItemLedgerEntry.SETRANGE("Item No.",'1000');
recItemLedgerEntry.SETRANGE("Location Code",'BLU');
recItemLedgerEntry.CALCSUMS(Inventory);
MESSAGE('%1',recItemLedgerEntry.Quantity);
Если вам нужно два экземпляра переменных одной и той же таблицы — можете использовать вместо двух переменных массив. Они работают независимо, как две отдельных переменных. Пара примеров:
CLEAR(recRecordVar1); => CLEAR(recRecordVar[1]);
recRecordVar1.SETRANGE(...) => recRecordVar[1].SETRANGE(…)
Для определения индекса массива можно использовать переменную, например:
recRecordVar1.RESET; => recRecordVar[intSomeInteger].RESET;
Работу с массивами можно использовать для временных таблиц. Они также работают независимо друг от друга, как и настоящие таблицы. НО ЗДЕСЬ БУДЕТ ВСЕГО ОДНА ВРЕМЕННАЯ ТАБЛИЦА! То есть, при создании переменной с индексом [1] она будет доступна и с индексом [2]. Пример (это начало работы с временной таблицей, поэтому записей там еще нет).
recRecord[1]."No." := '1');
recRecord[1].INSERT(FALSE);
recRecord[2].RESET;
recRecord[2].FINDFIRST;
MESSAGE('%1',recRecord[2]."No."); // здесь будет показано значение записи с индексом [1]!
Вычисление суммы по Общим бизнес группам и Общим товарным группам таблицы 15 G/L Entry
На SQL сделать это легко:
FROM dbo."CRONUS International Ltd_$G_L Entry"
GROUP BY "Gen_ Bus_ Posting Group","Gen_ Prod_ Posting Group"
ORDER BY "Gen_ Bus_ Posting Group","Gen_ Prod_ Posting Group"
В C/AL мы, к сожалению, не можем использовать инструкции SQL (или придется использовать ADO), поэтому есть другой способ. Я рекомендую всегда использовать его для суммирования в C/AL:
recGLEntry.SETCURRENTKEY(...); // попробуйте включить ключ, который можно использовать
// для быстрого получения фильтрованного набора данных
recGLEntry.SETRANGE(.....); // накладываем фильтры
IF recGLEntry.FINDSET THEN
REPEAT
// "tmpGLEntry" - временная таблица, где мы будем хранить итоги группировки
tmpGLEntry.RESET;
// надо постараться выбрать хороший ключ для фильтров
IF NOT tmpGLEntry.SETCURRENTKEY("Gen. Bus. Posting Group") THEN
IF NOT tmpGLEntry.SETCURRENTKEY("Gen. Prod. Posting Group") THEN ;
// Я накладываю фильтр на записи, по которым хочу сделать группировку
tmpGLEntry.setrange("Gen. Bus. Posting Group",recGLEntry."Gen. Bus. Posting Group");
tmpGLEntry.setrange("Gen. Prod. Posting Group",recGLEntry."Gen. Prod. Posting Group");
IF NOT tmpGLEntry.FINDFIRST THEN BEGIN
// Я не нашел запись, поэтому создал новую.
// Помните, что во время вставки записи вам нужен уникальный первичный ключ
// Это условие выполняется, поскольку каждая считанная мной recGLEntry - уникальна,
// поэтому можно просто делать INSERT "recGLEntry" в мою временную таблицу
tmpGLEntry := recGLEntry;
tmpGLEntry.insert(FALSE)
END ELSE BEGIN
// Я нашел требуемое сочетание, поэтому добавляю поля к суммеtmpGLEntry.Amount += recGLEntry.Amount;
tmpGLEntry.MODIFY(FALSE);
END;
UNTIL recGLEntry.NEXT = 0;
// Теперь у меня во временной таблице записи, которые содержат суммы по всем нужным мне комбинациям.
// Если вам необходима сортировка, понадобится ключ, а свойство MaintainSQLIndex можно отключить
// Еще один вариант - сделать новую таблицу со всеми нужными ключами и полям и использовать ее как
//временную. Вам НЕ НУЖНА лицензия на новую таблице, которую вы используете ТОЛЬКО в качестве временной!
// Теперь вы просто можете читать данные из временной таблицы, и делать с ними все, что угодно
tmpGLEntry.RESET;
FORM.RUNMODAL(0,tmpGLEntry);
Оригинал статьи называется «How to work with record-variables (version 2)?»

Автор: Андрей Стрельников
В области Navision - с 2003 года. Профессиональные интересы: NAV, MS SQL, .NET, BPMN, IT-менеджмент. Предметная область: логистика, финансы, склады, 3PL.
Количество статей, опубликованных автором: 86.
Такой вопрос, если нам нужно оперативно обновлять суммы в форме.
То есть у нас есть под таблицей поля с суммами некоторых столбцов, добавленных в SumIndexFields.
При этом на форму может быть наложен абсолютно любой фильтр. То есть, вторичный ключ у нас не резиновый.
Как лучше всего просуммировать столбцы?
Поможет ли на OnAfterGetRecord или каком-то другом триггере прописать что-то такое:
TempTable.COPY(Table);
TempTable.CALCSUMS(Amount1,Amount2);
Amount1Sum := TempTable.Amount1;
Amount2Sum := TempTable.Amount2
Если да, то на какой триггер повесить TempTable.DELETEALL, чтобы заново собрать все строки, которые мы суммируем?
И вообще, как правильнее всего это сделать?
Тест