При разработке на платформе 1С:Предприятие программисты часто сталкиваются с задачей массового обновления или дозаполнения данных в уже существующих документах. Типичный пример — добавление новых реквизитов в табличную часть (ТЧ), которые нужно заполнить на основе старых данных за прошедший период. Разберем, как реализовать это правильно, избегая типичных ошибок производительности и логики.
Рассмотрим ситуацию, когда разработчик пытается получить форму документа через ПолучитьФорму(), программно заполнить её табличную часть и вызвать метод Форма.Записать(). Проанализируем, почему этот путь является тупиковым:
ПриОткрытии, ПриЧтенииНаСервере и т.д.), что требует огромных вычислительных ресурсов.Вывод: Для групповой обработки документов всегда используйте объектную модель (ПолучитьОбъект()), работая напрямую с данными в базе.
Часто новички пишут код, в котором метод ТЧ.Очистить() вызывается внутри цикла обхода выборки запроса. Это приводит к тому, что на каждой итерации старые строки удаляются, и в итоге в документе сохраняется только та строка, которая была обработана последней. Посмотрим на неправильный пример:
// ОШИБОЧНЫЙ КОД
Пока Выборка.Следующий() Цикл
Объект = Выборка.Ссылка.ПолучитьОбъект();
Объект.Товары.Очистить(); // Ошибка! Очистка происходит внутри цикла по строкам
НоваяСтрока = Объект.Товары.Добавить();
// заполнение реквизитов...
Объект.Записать();
КонецЦикла;
Чтобы исправить эту ситуацию, необходимо четко разделять логику получения ссылки на документ и логику обработки его строк.
Рассмотрим пошагово, как реализовать корректное заполнение. Мы разделим процесс на получение данных и их запись. Выясним причину, по которой важно группировать данные по ссылке на документ.
Шаг 1. Оптимизация запроса
Если мы выбираем данные напрямую из табличной части, запрос вернет столько строк, сколько их в документах. Чтобы не вызывать ПолучитьОбъект() десять раз для документа, в котором десять строк, применим группировку или обход по группировкам.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Перемещение.Ссылка КАК Ссылка,
| Перемещение.Номенклатура КАК Номенклатура,
| Перемещение.Количество КАК Количество
|ИЗ
| Документ.ПеремещениеТМЦ.Товары КАК Перемещение
|ГДЕ
| Перемещение.Ссылка.Дата МЕЖДУ &ДатаНач И &ДатаКон
|ИТОГИ ПО
| Ссылка"; // Группируем по документу
Запрос.УстановитьПараметр("ДатаНач", ДатаНач);
Запрос.УстановитьПараметр("ДатаКон", ДатаКон);
Результат = Запрос.Выполнить();
Шаг 2. Обход результата и запись объекта
Используем метод Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам). Это позволит нам один раз открыть объект документа, очистить его табличную часть (если требуется полная перезапись) и заполнить её всеми строками из вложенной выборки.
ВыборкаДокументов = Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
Пока ВыборкаДокументов.Следующий() Цикл
// Получаем объект один раз для всего документа
ДокОбъект = ВыборкаДокументов.Ссылка.ПолучитьОбъект();
// Если нужно полностью заменить ТЧ:
ДокОбъект.Товары.Очистить();
ВыборкаСтрок = ВыборкаДокументов.Выбрать();
Пока ВыборкаСтрок.Следующий() Цикл
НоваяСтрока = ДокОбъект.Товары.Добавить();
// Используем ЗаполнитьЗначенияСвойств для сокращения кода
ЗаполнитьЗначенияСвойств(НоваяСтрока, ВыборкаСтрок);
// Дозаполняем специфические или новые реквизиты
НоваяСтрока.ВидПотребности = Перечисления.ВидыПотребностей.Внешняя;
НоваяСтрока.НоменклатураГП = ВыборкаСтрок.Номенклатура;
КонецЦикла;
// Записываем объект
Попытка
ДокОбъект.Записать(РежимЗаписиДокумента.Запись);
Сообщить("Документ обновлен: " + ДокОбъект);
Исключение
Сообщить("Не удалось записать: " + ДокОбъект + ". Ошибка: " + ОписаниеОшибки());
КонецПопытки;
КонецЦикла;
Когда документов тысячи, стандартная запись может занять значительное время. Проанализируем инструменты, которые предоставляет платформа для ускорения этого процесса.
1. Использование ОбменДанными.Загрузка
Перед вызовом метода Записать() установите свойство ДокОбъект.ОбменДанными.Загрузка = Истина;. Это отключит выполнение тяжелых проверок в модуле объекта и подписки на события (например, контроль остатков, проверку прав доступа к регистрам). Это безопасно, если вы уверены в корректности записываемых данных.
2. Использование транзакций
Оберните цикл обработки в транзакцию. Это сократит количество обращений к диску для фиксации изменений СУБД. Рекомендуется фиксировать транзакцию порциями (например, по 200 документов), чтобы избежать переполнения лога транзакций.
НачатьТранзакцию();
// ... цикл обработки документов ...
ЗафиксироватьТранзакцию();
3. Метод Загрузить()
Если структура таблицы значений (ТЗ) полностью совпадает с колонками табличной части, можно использовать метод ДокОбъект.Товары.Загрузить(ВашаТаблицаЗначений);. Это работает на уровне платформы значительно быстрее, чем перебор строк в цикле Для Каждого.
Проанализировав ситуацию, мы выяснили, что для успешного перезаполнения ТЧ необходимо:
ПолучитьОбъект().ЗаполнитьЗначенияСвойств для минимизации ручного копирования данных между выборкой и строкой ТЧ.Соблюдение этих правил гарантирует стабильную работу системы и целостность данных в информационной базе.