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