В процессе разработки конфигураций на платформе 1С:Предприятие часто возникает задача обогащения данных табличной части (ТЧ) документа информацией, хранящейся в регистрах накопления. Рассмотрим, как правильно спроектировать решение этой задачи, избегая классических ошибок производительности и потери данных.
Основная сложность заключается в том, что данные в регистрах накопления (особенно в оборотных) требуют корректной агрегации и фильтрации. Попытка перебора строк табличной части и выполнения запроса «в лоб» внутри цикла — это путь к критическому замедлению работы системы, особенно если документов много, а регистр содержит миллионы записей.
Самым эффективным способом является получение всех необходимых данных одним запросом до начала заполнения табличной части. Разберем шаги, которые помогут нам добиться результата.
Обороты регистра накопления. Это позволяет системе автоматически выполнить группировку данных.Вместо выполнения запроса внутри цикла, который потребует множества обращений к серверу базы данных, мы сформируем один мощный пакетный запрос. Рассмотрим пример кода, который позволит эффективно извлечь данные:
Запрос = Новый Запрос;
Запрос.Текст =
\"ВЫБРАТЬ
| ТЗ.Сделка КАК Сделка
|ПОМЕСТИТЬ ВТ_Сделки
|ИЗ
| &ТЗ КАК ТЗ
|;
|ВЫБРАТЬ
| ВТ_Сделки.Сделка КАК Сделка,
| ЕСТЬNULL(РегистрОбороты.СуммаВалОборот, 0) КАК Расходы
|ИЗ
| ВТ_Сделки КАК ВТ_Сделки
|ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ДополнительныеРасходыПоСделке.Обороты(&НачалоПериода, &КонецПериода, , ) КАК РегистрОбороты
|ПО ВТ_Сделки.Сделка = РегистрОбороты.Сделка\";
Запрос.УстановитьПараметр(\"ТЗ\", Объект.Проекты.Выгрузить());
Запрос.УстановитьПараметр(\"НачалоПериода\", НачалоГода(ТекущаяДата()));
Запрос.УстановитьПараметр(\"КонецПериода\", ТекущаяДата());
РезультатЗапроса = Запрос.Выполнить().Выгрузить();
Важно помнить: метод Загрузить() полностью очищает табличную часть. Если у вас в Объект.Проекты уже есть другие заполненные колонки, их данные будут уничтожены. Чтобы этого избежать, мы используем алгоритм поиска по индексу:
// Создаем индекс для быстрого поиска
РезультатЗапроса.Индексы.Добавить(\"Сделка\");
Для Каждого СтрокаТЧ Из Объект.Проекты Цикл
НайденнаяСтрока = РезультатЗапроса.Найти(СтрокаТЧ.Сделка, \"Сделка\");
Если НайденнаяСтрока <> Неопределено Тогда
СтрокаТЧ.РасходыПоСделке = НайденнаяСтрока.Расходы;
КонецЕсли;
КонецЦикла;
Проанализируем преимущества такого подхода:
ЛЕВОЕ СОЕДИНЕНИЕ гарантирует, что если по сделке нет расходов, строка не исчезнет из документа, а просто получит нулевое значение (благодаря функции ЕСТЬNULL).Таким образом, комбинируя временные таблицы и последующий обход коллекции, вы получаете надежный, профессиональный и быстрый механизм заполнения табличной части, который будет работать стабильно даже при больших объемах данных в информационной базе.