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