Почему объект регистрируется к обмену, но не передается в базу-приемник при проверке ссылки в правилах регистрации?

Программист 1С v8.3 (Управляемые формы) 1С:Комплексная автоматизация IT и автоматизация бизнеса
← На главную

При настройке обменов данными между конфигурациями 1С часто возникает задача: передавать новый объект в базу-приемник только один раз при его создании, игнорируя все последующие изменения и перезаписи в базе-источнике.

Попытка реализовать данную логику через типовые правила регистрации объектов (ПРО) с условием проверки ссылки часто приводит к неожиданному поведению: объект успешно регистрируется на узле плана обмена, номер пакета при выгрузке увеличивается, но данные в базу-приемник так и не попадают. Разберем детально, почему это происходит и какими способами можно корректно решить задачу разовой выгрузки.

Рассмотрим код, который обычно пытаются использовать в обработчике Перед обработкой правил регистрации объектов:


Если НЕ Объект.Ссылка.Пустая() Тогда
    Отказ = Истина;
КонецЕсли;

Причина проблемы: двойное выполнение правил регистрации

Проанализируем внутреннюю архитектуру подсистемы обмена данными Библиотеки стандартных подсистем (БСП). Алгоритмы правил регистрации объектов (ПРО) выполняются платформой и БСП дважды:

  1. В момент интерактивной или программной записи объекта в базу: срабатывает подписка на события. В этот момент для нового объекта ссылка еще не зафиксирована в базе (или проверяется состояние до фиксации транзакции), поэтому условие Объект.Ссылка.Пустая() возвращает Истина, отказ не срабатывает, и запись об изменении объекта успешно помещается в таблицу регистрации изменений плана обмена.
  2. В момент фактического формирования пакета выгрузки: регламентное задание или мастер обмена считывает зарегистрированные изменения из плана обмена и повторно прогоняет объект через правила регистрации для валидации актуальности условий перед отправкой. На этом шаге объект уже физически сохранен в базе данных. Метод Объект.Ссылка.Пустая() возвращает Ложь, условие НЕ Объект.Ссылка.Пустая() срабатывает и присваивает Отказ = Истина.

В результате БСП считает, что объект больше не соответствует правилам выгрузки, молча исключает его из формируемого сообщения обмена и удаляет запись о регистрации из плана обмена. Пакет считается успешно отправленным, счетчик номеров сообщений увеличивается, но полезные данные объекта в XML/JSON-файл не попадают.

Способ 1. Фиксация факта первой отправки через регистр сведений

Для корректной реализации разовой отправки нам необходимо где-то хранить признак того, что объект уже был фактически выгружен. Самый надежный подход — использование непериодического регистра сведений (например, ИсторияВыгрузкиОбъектов) с измерениями Объект и УзелОбмена.

Разберем по шагам реализацию этого механизма:

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

При такой схеме новый объект успешно регистрируется и выгружается в первый раз, так как записи в регистре еще нет. При второй проверке в момент отправки записи в регистре также еще нет — объект выгружается, и только в событии После выгрузки создается запись. При всех последующих изменениях объекта в источнике запрос вернет результат, и регистрация будет заблокирована.

Способ 2. Отключение авторегистрации и регистрация в подписке на события

Если нет возможности менять состав правил выгрузки, можно управлять регистрацией на уровне метаданных и подписок на события:

  1. В составе нужного плана обмена для конкретного документа или справочника установим свойство Авторегистрация = Запретить.
  2. В подписке на событие ПередЗаписью проверим, является ли объект новым, и сохраним этот факт во временные свойства:
    
    Если Объект.ЭтоНовый() Тогда
        Объект.ДополнительныеСвойства.Вставить("ЭтоНовыйОбъектДляОбмена", Истина);
    КонецЕсли;
    
  3. В подписке на событие ПриЗаписи выполним явную регистрацию объекта на узле плана обмена:
    
    Если Объект.ДополнительныеСвойства.Свойство("ЭтоНовыйОбъектДляОбмена") Тогда
        ПланыОбмена.ЗарегистрироватьИзменения(УзелДляОбмена, Объект.Ссылка);
    КонецЕсли;
    
  4. В правилах регистрации (ПРО) при этом не устанавливаем никаких условий на проверку ссылки.

Способ 3. Запрет перезаписи на стороне базы-приемника

Если бизнес-требование состоит в том, чтобы изменения из базы-источника не затирали данные, скорректированные в базе-приемнике, логику можно перенести на сторону загрузки:

  1. В правилах конвертации (или в модулях интеграции EnterpriseData на стороне приемника) в событии Перед записью полученных данных найдем существующий объект в базе.
  2. Если объект уже присутствует в информационной базе приемника, установим Отказ = Истина. В таком случае новые объекты будут успешно создаваться, а обновления существующих — игнорироваться без ошибок обмена.
← На главную