При работе с регистрами бухгалтерии в платформе 1С:Предприятие разработчики часто сталкиваются с необходимость модифицировать отдельные проводки в документе. Возникает логичный вопрос: можно ли наложить отбор на объект РегистрБухгалтерииНаборЗаписей не только по полю Регистратор, но и по другим реквизитам — например, по счету или субконто?
Рассмотрим устройство механизма записи регистра бухгалтерии, выясним причины архитектурных ограничений платформы и разберем практические способы решения этой задачи при работе с большими объемами данных.
В платформе 1С:Предприятие объект РегистрБухгалтерииНаборЗаписей устроен таким образом, что его коллекция Отбор содержит только одно доступное поле — Регистратор. Попытка установить отбор по субконто, измерениям, ресурсам или периоду на уровне этого объекта не предусмотрена разработчиками платформы.
Причина заключается в физической модели хранения данных на уровне СУБД:
Записать() платформа полностью удаляет все существующие записи регистра, принадлежащие данному регистратору, и записывает на их место новый набор.Если требуется изменить конкретные проводки (например, поменять значение субконто у пары строк), алгоритм работы строится через промежуточный объект ТаблицаЗначений. Проанализируем пошаговый процесс реализации:
Рассмотрим пример программного кода для реализации этого подхода:
// Создаем набор записей и задаем единственно возможный отбор по регистратору
НаборЗаписей = РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(СсылкаНаДокумент);
НаборЗаписей.Прочитать();
// Выгружаем проводки в таблицу значений
ТаблицаПроводок = НаборЗаписей.Выгрузить();
// Индексируем колонку для ускорения поиска на больших объемах
ТаблицаПроводок.Индексы.Добавить("СубконтоДт1");
// Формируем условия поиска целевых строк
ПараметрыПоиска = Новый Структура;
ПараметрыПоиска.Вставить("СубконтоДт1", СтароеСубконто);
НайденныеСтроки = ТаблицаПроводок.НайтиСтроки(ПараметрыПоиска);
// Модифицируем найденные проводки
Для Каждого СтрокаТЗ Из НайденныеСтроки Цикл
СтрокаТЗ.СубконтоДт1 = НовоеСубконто;
КонецЦикла;
// Загружаем данные обратно и записываем набор
НаборЗаписей.Загрузить(ТаблицаПроводок);
// Отключаем лишние проверки для ускорения записи
НаборЗаписей.ОбменДанными.Загрузка = Истина;
НаборЗаписей.Записать();
Если документ содержит 10 000–20 000 и более проводок, выгрузка и полная перезапись всего набора ради нескольких строк создает колоссальную нагрузку на СУБД и таблицы итогов. Для оптимизации таких операций рекомендуется применять следующие архитектурные подходы:
НаборЗаписей.ОбменДанными.Загрузка = Истина при программной перезаписи. Это отключает выполнение тяжелых обработчиков событий модуля набора записей.