Как настроить синхронизацию EnterpriseData, чтобы не перезаписывать существующие документы в базе-приемнике

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

При использовании технологии EnterpriseData (синхронизация через универсальный формат) разработчики часто сталкиваются со стандартным поведением системы: если объект (например, документ «Реализация товаров и услуг») уже существует в базе-приемнике, то при повторной загрузке из источника он будет полностью перезаписан. Это создает проблемы, если в базе-приемнике в документ вносились ручные правки или если бизнес-логика подразумевает неизменность данных после первичного получения. В этой статье мы подробно разберем, как изменить это поведение с помощью механизмов Конвертации данных 3.0 и расширений конфигурации.

Понимание механики работы обработчика «Перед записью полученных данных»

Для реализации нашей задачи необходимо вмешаться в процесс загрузки объекта в тот момент, когда система уже нашла существующий документ в информационной базе (ИБ), но еще не успела применить к нему изменения из входящего файла. В архитектуре EnterpriseData за это отвечает специализированный обработчик ПередЗаписьюПолученныхДанных.

Рассмотрим ключевые параметры, которые доступны нам в этом обработчике:

Проанализируем основную идею решения: если ДанныеИБ не равно Неопределено, значит, документ уже есть в системе, и нам нужно отменить его обновление. Для этого достаточно присвоить параметру ПолученныеДанные значение Неопределено. Это служит сигналом для транспортного механизма обмена пропустить этап записи данного объекта.

Способ 1. Реализация через расширение конфигурации (без изменения правил в КД 3.0)

Если мы не хотим или не имеем возможности вносить изменения в саму схему обмена через конфигурацию «Конвертация данных 3.0», мы можем воспользоваться механизмом расширений. Это наиболее оперативный способ решить задачу, изменив поведение конкретного ПКО (Правила Конвертации Объекта) непосредственно в коде модуля менеджера обмена.

Разберем по шагам, как это реализовать. Нам необходимо найти в модуле менеджера обмена (обычно это МенеджерОбменаЧерезУниверсальныйФормат или аналогичный) процедуру, отвечающую за обработчик ПередЗаписьюПолученныхДанных конкретного документа. Например, для реализации товаров и услуг процедура может называться ПКО_Документ_РеализацияТоваровУслуг_ПередЗаписьюПолученныхДанных.

Посмотрим на пример кода, который мы разместим в расширении:


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

КонецПроцедуры

Выясним, что происходит в этом коде: конструкция &Вместо полностью перехватывает управление. Если объект новый, мы используем ПродолжитьВызов, чтобы отработала стандартная логика заполнения. Если же объект найден, мы просто выходим из процедуры, установив ПолученныеДанные = Неопределено, тем самым блокируя перезапись.

Способ 2. Редактирование правил в конфигурации «Конвертация данных 3.0»

Правильный архитектурный подход заключается в изменении самих правил обмена. Это позволит сохранить логику при обновлении конфигурации и сделает настройку более прозрачной. Разберем алгоритм действий:

  1. Откроем базу Конвертация данных 3.0 и загрузим в нее текущие настройки обмена вашей конфигурации.
  2. Перейдем в раздел «Правила конвертации объектов» и найдем нужное нам ПКО (например, для документа РеализацияТоваровУслуг).
  3. Найдем вкладку «Обработчики событий» и выберем событие «Перед записью полученных данных».
  4. Вставим следующий программный код:

Если ДанныеИБ <> Неопределено Тогда
    // Объект уже есть в базе, отменяем загрузку изменений
    ПолученныеДанные = Неопределено;
КонецЕсли;

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

Проблема «Эха» и зацикливания обмена

Рассмотрим критически важный нюанс, который часто упускают из виду. Технология EnterpriseData работает по принципу отслеживания версий. Если мы запретили изменять объект в приемнике, его версия в приемнике останется старой, в то время как источник «считает», что данные должны быть обновлены.

Это может привести к неприятным последствиям:

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

Мягкое обновление: когда нужно обновить только часть полей

Иногда задача стоит сложнее: нужно не просто «не затирать» весь документ, а сохранить лишь определенные реквизиты (например, ответственного или комментарий), разрешив при этом обновлять табличную часть с товарами. В этом случае мы не обнуляем ПолученныеДанные, а выполняем выборочное копирование.

Проанализируем пример кода для «мягкого» обновления:


Если ДанныеИБ <> Неопределено Тогда
    // Получаем объект из базы для редактирования
    ДокументОбъект = ДанныеИБ.ПолучитьОбъект();
    
    // Предположим, мы хотим сохранить Комментарий, который ввели в приемнике вручную
    // Мы берем значение из существующего ДокументОбъект и перезаписываем им 
    // то, что пришло в ПолученныеДанные
    ПолученныеДанные.Комментарий = ДокументОбъект.Комментарий;
    
    // Таким образом, при записи документа все поля обновятся, 
    // а Комментарий останется нетронутым.
КонецЕсли;

Такой подход позволяет гибко настраивать правила «сосуществования» данных из разных информационных баз, обеспечивая целостность учета.

Альтернативные методы фильтрации

Посмотрим на ситуацию шире. Если нам нужно запретить обновление абсолютно всех документов определенного типа для конкретного узла, можно использовать глобальный обработчик ПриПолученииДанныхОтУзла в модуле обмена. Там можно проанализировать входящее сообщение еще до начала его парсинга в объекты 1С и программно удалить из него XML-узлы, соответствующие ненужным документам. Это более трудоемкий, но максимально производительный метод, так как система не будет тратить ресурсы на создание объектов в памяти, которые всё равно не будут записаны.

Также не забывайте проверять настройки Полей поиска. Если логика поиска настроена некорректно, система может не найти существующий документ (ДанныеИБ будет Неопределено) и создаст дубль вместо того, чтобы попасть в наше условие отмены записи. Убедитесь, что поиск по ключевым полям (Номер, Дата) или по внутреннему идентификатору (GUID) работает стабильно.

← На главную