При настройке обмена через конфигурацию «Конвертация данных» многие разработчики сталкиваются с ситуацией: необходимо программно дозаполнить движения загружаемого документа в регистре сведений. Мы пишем код в обработчике После загрузки, отладчик показывает, что код выполняется без ошибок, данные присваиваются, но по итогу в базе данных изменения не сохраняются (поля остаются пустыми). Давайте разберем эту ситуацию по шагам и выясним причину такого поведения.
Рассмотрим типичный код, который разработчики добавляют в обработчик правила конвертации объекта (ПКО) После загрузки:
НаборЗаписей = РегистрыСведений.События.СоздатьНаборЗаписей();
ДатаНабора = ТекущаяДата();
НаборЗаписей.Отбор.Регистратор.Установить(Объект.Ссылка);
НаборЗаписей.Прочитать();
Для каждого СтрРег из НаборЗаписей цикл
СтрРег.ГруппаСобытия = Справочники.ГруппыСобытий.НачислениеБонуса;
КонецЦикла;
НаборЗаписей.Записать();
На первый взгляд, все логично. Если запустить этот фрагмент во внешней обработке — он отработает безупречно. Однако внутри процесса загрузки данных он не дает нужного результата. Проанализируем причины:
НаборЗаписей.Записать(), а затем продолжит стандартную загрузку и перезапишет движения из файла XML поверх ваших ручных правок.ОбработкаПроведения модуля документа. Модуль документа заново сформирует записи по регистрам, полностью затерев ваши программные корректировки.Объект и ее коллекцией Объект.Движения.Разберем несколько корректных подходов к решению данной проблемы, двигаясь от самых правильных к альтернативным.
Самый корректный подход в «Конвертации данных» — отказаться от написания программного кода там, где это не требуется. Мы можем решить задачу настройкой Правил Конвертации Объектов (ПКО) и Правил Конвертации Свойств (ПКС).
Создайте отдельное ПКО для нужного регистра сведений (в нашем случае РегистрыСведений.События) или настройте ПКС для табличной части движений внутри ПКО самого документа. Нужное значение (например, Справочники.ГруппыСобытий.НачислениеБонуса) можно передавать или вычислять еще на этапе формирования файла выгрузки. Таким образом, принимающая база получит готовый XML с уже заполненными данными.
Если визуальная настройка не подходит, и без кода не обойтись, мы должны отказаться от создания нового набора записей. Вместо этого модифицируем саму коллекцию движений текущего объекта в памяти. Платформа сама запишет ее в конце транзакции.
Изменим наш подход в обработчике После загрузки:
// Не используем прямое обращение к БД
// Работаем с коллекцией движений текущего загружаемого Объекта
ДвиженияСобытия = Объект.Движения.События;
ДвиженияСобытия.Прочитать(); // Читаем текущие движения, если они уже есть
Для Каждого СтрРег Из ДвиженияСобытия Цикл
СтрРег.ГруппаСобытия = Справочники.ГруппыСобытий.НачислениеБонуса;
КонецЦикла;
// Мы НЕ вызываем ДвиженияСобытия.Записать() !
// Устанавливаем флаг, чтобы платформа записала модифицированный набор сама
ДвиженияСобытия.Записывать = Истина;
Если документ проводит сам себя, настройте обмен так, чтобы документы загружались в режиме простой записи, без автоматического проведения и без переноса движений. В этом случае задача сводится к тому, чтобы доработать логику самой базы-приемника. Загруженные документы можно будет проводить регламентным заданием, и тогда отработает стандартный механизм регистратора.
Для полноты картины упомянем решение, к которому прибегнул автор оригинального вопроса. Он использовал глобальный обработчик После загрузки данных (срабатывает, когда вся порция данных уже загружена в базу).
В этом обработчике пишется запрос к базе, который ищет все записи регистра с пустым полем ГруппаСобытия за период загрузки, и пакетно их обновляет. Мы не рекомендуем данный подход, так как он сильно замедляет обмен и является «костылем», однако в крайних случаях (например, когда обмен уже идет и нужно срочно исправить данные) он имеет место быть.
Обработчик После загрузки в «Конвертации данных» концептуально не предназначен для инициирования отдельных транзакций записи подчиненных наборов данных. Его задача — модификация свойств переменной Объект перед её сохранением платформой. Посмотрим на эту ситуацию как на правило: всегда модифицируйте свойства объекта в кэше, а сохранение оставьте стандартным механизмам платформы.