Как в Конвертации данных передать ссылку на связанный объект при обратной связи между справочниками?

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

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

Проанализируем конкретную практическую задачу. В конфигурации-источнике существует справочник УсловияОбслуживанияПартнеров, к которому привязан контрагент. В конфигурации-приемнике эти условия конвертируются в справочник ТорговыеТочки. При этом в приемнике у справочника Контрагенты присутствует реквизит ТорговаяТочка, ссылающийся на элемент торговой точки. Задача заключается в том, чтобы при выгрузке контрагента корректно заполнить его реквизит нужной ссылкой, несмотря на то, что в источнике в самом контрагенте этого реквизита нет.

Способ 1. Добавление виртуального свойства в ПКС с вычислением значения ПередВыгрузкой

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

  1. Откроем правило конвертации объекта (ПКО) Контрагенты.
  2. В таблице правил конвертации свойств добавим новую строку.
  3. Поле Приемник заполняем именем реквизита в целевой базе — ТорговаяТочка.
  4. Поле Источник оставляем пустым.
  5. В колонке Правило указываем ПКО конвертации условий в точки: УсловияОбслуживанияПартнеров_ТорговыеТочки.
  6. В обработчике события ПередВыгрузкой данного свойства программно определяем значение источника.

Посмотрим на пример кода в обработчике ПередВыгрузкой свойства ТорговаяТочка:


// В переменной Источник находится текущая ссылка на выгружаемого контрагента
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ ПЕРВЫЕ 1
    |	Условия.Ссылка КАК Ссылка
    |ИЗ
    |	Справочник.УсловияОбслуживанияПартнеров КАК Условия
    |ГДЕ
    |	Условия.Контрагент = &Контрагент";

Запрос.УстановитьПараметр("Контрагент", Источник);
Выборка = Запрос.Выполнить().Выбрать();

Если Выборка.Следующий() Тогда
    Значение = Выборка.Ссылка;
Иначе
    ВыгрузитьОбъект = Ложь; // Если точка не найдена, свойство не выгружаем
КонецЕсли;

В этом случае механизм конвертации берет полученную ссылку на УсловияОбслуживанияПартнеров из переменной Значение, находит для нее указанное правило ПКО и выгружает ее в XML. При загрузке в базу-приемник сформированная ссылка автоматически запишется в реквизит ТорговаяТочка контрагента.

Способ 2. Оптимизация производительности: устранение проблемы N+1 запросов

Разберем важный нюанс: если выполнять отдельный запрос в обработчике ПередВыгрузкой для каждого контрагента, выгрузка десятков тысяч записей займет значительное время из-за многократных обращений к СУБД. Чтобы оптимизировать процесс, применим кэширование связей через глобальную коллекцию Параметры.

  1. В глобальном обработчике правил обмена ПередВыгрузкойДанных выполняем один общий запрос ко всей базе и формируем соответствие.
  2. В ПКС реквизита просто получаем значение из подготовленной таблицы или соответствия по ключу ссылки.

Посмотрим, как выглядит код в обработчике ПередВыгрузкойДанных:


Параметры.Вставить("КэшТорговыхТочек", Новый Соответствие);

Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Условия.Контрагент КАК Контрагент,
    |	Условия.Ссылка КАК ТорговаяТочка
    |ИЗ
    |	Справочник.УсловияОбслуживанияПартнеров КАК Условия
    |ГДЕ
    |	Условия.Контрагент <> ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка)";

Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
    Параметры.КэшТорговыхТочек.Вставить(Выборка.Контрагент, Выборка.ТорговаяТочка);
КонецЦикла;

Теперь код в обработчике ПередВыгрузкой свойства ТорговаяТочка у ПКО Контрагенты становится предельно простым и быстрым:


Точка = Параметры.КэшТорговыхТочек[Источник];
Если Точка <> Неопределено Тогда
    Значение = Точка;
Иначе
    ВыгрузитьОбъект = Ложь;
КонецЕсли;

Способ 3. Передача данных через механизм «ВходящиеДанные»

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

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

Пример кода в обработчике ПослеВыгрузки ПКО УсловияОбслуживанияПартнеров:


Если ЗначениеЗаполнено(Источник.Контрагент) Тогда
    ВходящиеДанныеДляКонтрагента = Новый Структура;
    ВходящиеДанныеДляКонтрагента.Вставить("ТорговаяТочка", Источник.Ссылка);
    
    ВыгрузитьПоПравилу(
        Источник.Контрагент, 
        , 
        ВходящиеДанныеДляКонтрагента, 
        , 
        "Контрагенты"
    );
КонецЕсли;

Важные практические рекомендации по синхронизации

При настройке подобных связей обратим внимание на следующие технические особенности:

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