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