Как в 1С:Конвертация данных 2.1 перенести данные из одного справочника в другой с подменой GUID?

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

При настройке правил обмена в «1С:Конвертация данных 2.1» (КД 2) разработчики часто сталкиваются с нестандартными задачами трансформации данных. Одна из таких сложных ситуаций — необходимость изменить уникальный идентификатор (GUID/УИД) объекта непосредственно в процессе переноса, особенно когда типы данных в источнике и приемнике различаются.

В этой статье мы подробно разберем сценарий, когда в базе-источнике есть документ, ссылающийся на простой СправочникА (содержащий в себе сложный СправочникБ), а в базе-приемнике аналогичный документ должен ссылаться напрямую на СправочникБ, но с идентификатором (GUID) от СправочникаА. Мы проанализируем ошибки проектирования таких правил, выясним, почему стандартные подходы могут приводить к появлению «битых» ссылок, и рассмотрим три практических способа решения этой задачи.

Почему простая подмена GUID в обработчике «После загрузки» не работает?

Типичная ошибка начинающих разработчиков КД 2 — попытка передать нужный GUID в параметре объекта и перезаписать его в базу-приемник на этапе загрузки (например, в обработчике После загрузки). Схема выглядит логично: объект создается, мы перехватываем его, генерируем новый УИД на основе переданного параметра и записываем.

Однако при такой схеме ссылки в загружаемых документах гарантированно окажутся «битыми» (будет отображаться объект со строкой <Объект не найден...>). Давайте разберем причину этого поведения, скрытую в архитектуре работы обработки УниверсальныйОбменДаннымиXML:

  1. Таблица соответствия ссылок: Во время загрузки данных КД ведет во внутренней памяти специальную карту сопоставления. В ней фиксируется связь между исходным идентификатором из XML-файла и созданной (или найденной) ссылкой в информационной базе приемника.
  2. Момент подмены: Если мы принудительно меняем GUID созданного объекта в коде После загрузки, объект записывается в базу данных с новым идентификатором. Но внутренняя таблица КД об этом «не знает» — в ней по-прежнему зарегистрировано сопоставление со старым, промежуточным идентификатором.
  3. Результат: Когда следом начинает загружаться документ, содержащий ссылку на этот справочник, КД обращается к своей таблице сопоставлений, находит там старый идентификатор и записывает его в реквизит документа. В итоге документ ссылается на пустой (несуществующий) идентификатор, а реально созданный элемент справочника «сиротеет» в базе с новым GUID.

Чтобы избежать этой проблемы, подмену идентификатора необходимо делать на этапе поиска или сериализации в XML, чтобы КД сразу зафиксировала правильный GUID в своей карте соответствий. Рассмотрим рабочие методы реализации.

Способ 1. Лучшая практика — использование обработчика «Поля поиска»

Это самый чистый, надежный и простой в поддержке способ. Он не требует ручного вмешательства в XML-структуру и избавляет от необходимости прописывать код переноса для десятков реквизитов вручную.

Идея заключается в том, чтобы передать GUID СправочникаА в качестве параметра поиска для СправочникаБ и принудительно инициализировать объект по этой ссылке еще до начала его заполнения.

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

Шаг 1. Передача GUID из документа-источника

В ПРАВИЛЕ Конвертации Свойств (ПКС) документа, в котором выгружается ссылка на справочник, в обработчике Перед выгрузкой мы перехватываем GUID владельца и передаем его во входящие данные:


// Инициализируем структуру входящих данных для ПКО СправочникаБ
ИсходящиеДанные = Новый Структура;
Если ЗначениеЗаполнено(Источник.РеквизитСправочникаА) Тогда
    // Получаем строковое представление GUID справочника А
    ИсходящиеДанные.Вставить("ГУИД_А", Строка(Источник.РеквизитСправочникаА.УникальныйИдентификатор()));
КонецЕсли;

Шаг 2. Настройка ПКО СправочникБ -> СправочникБ

Перейдем в ПРАВИЛО Конвертации Объектов (ПКО) СправочникБ:

  1. В настройках ПКО снимите галочку Искать объект приемника по внутреннему идентификатору источника. Это заставит КД использовать алгоритмы поиска вместо автоматического сопоставления по «родному» GUID.
  2. Добавьте новое ПКС в табличную часть правил. Источник оставьте пустым, а в качестве Приемника выберите Параметры. Назовите параметр, например, ГУИД_А.
  3. Установите для этого свойства флаги Передавать данные в параметр и Использовать при поиске.
  4. В обработчике Перед выгрузкой этого ПКС напишите код для получения переданного значения:

Если ВходящиеДанные <> Неопределено Тогда
    Значение = ВходящиеДанные.Получить("ГУИД_А");
КонецЕсли;

Шаг 3. Подмена ссылки в обработчике «Поля поиска»

Теперь откройте обработчик Поля поиска в ПКО СправочникБ и пропишите код инициализации объекта по новому GUID:


ГУИД = "";
Если ПараметрыОбъекта <> Неопределено Тогда
    ГУИД = ПараметрыОбъекта.Получить("ГУИД_А");
КонецЕсли;

Если Не ПустаяСтрока(ГУИД) Тогда
    НовыйУИД = Новый УникальныйИдентификатор(ГУИД);
    
    // Генерируем или находим ссылку в приемнике с УИД-ом справочника А
    СсылкаНаОбъект = Справочники.СправочникБ.ПолучитьСсылку(НовыйУИД);
    
    // Прекращаем дальнейший стандартный поиск КД
    ПрекратитьПоиск = Истина;
КонецЕсли;

Как это работает: Установив флаг ПрекратитьПоиск = Истина и заполнив переменную СсылкаНаОбъект, мы явно указываем КД использовать именно эту ссылку. Если элемента с таким GUID еще нет в базе-приемнике, платформа создаст его при записи свойств. Если он уже существовал, КД просто обновит его реквизиты. При этом таблица соответствий заполнится корректно, и документы запишутся без «битых» ссылок.

Способ 2. Создание разнородного ПКО (СправочникА -> СправочникБ)

Второй способ базируется на стандартном механизме КД, когда ПКО настраивается между разными типами объектов. Если источником выступает СправочникА, а приемником — СправочникБ, КД по умолчанию автоматически запишет GUID источника (то есть СправочникаА) в создаваемый объект приемника (СправочникБ).

Проблема этого подхода в исходной задаче — данные для заполнения СправочникаБ находятся внутри его реквизитов в источнике, а не в самом СправочникеА. Нам придется перенаправлять свойства.

Рассмотрим по шагам реализацию этого метода:

  1. Создайте ПКО, где Источник — СправочникА, а Приемник — СправочникБ.
  2. В настройках ПКО оставьте включенной автоматическую синхронизацию по GUID (поиск по УИД источника).
  3. Для каждого переносимого реквизита в ПКС (включая табличные части) вам потребуется перенаправить источник получения данных. Для этого в обработчике Перед выгрузкой каждого ПКС пишется код:

// Перенаправляем получение данных на внутренний реквизит Справочника Б
Значение = Источник.РеквизитСправочникаБ[ИмяРеквизита];

Если у СправочникаБ очень много реквизитов и табличных частей, прописывать такой код для каждого свойства вручную может быть трудоемко. Этот способ отлично подходит, если структура справочника-приемника простая или состоит всего из нескольких полей.

Способ 3. Прямая модификация XML-узла GUID при выгрузке

Этот способ можно назвать «низкоуровневым хаком». Мы принудительно заменяем выгружаемый узел идентификатора в XML-файле обмена на нужный нам GUID еще на стороне базы-источника.

Давайте проанализируем, как это сделать:

  1. В ПКС документа (где выгружается реквизит-справочник) в обработчике Перед выгрузкой перенаправляем выгрузку на внутренний СправочникБ:

Значение = Источник.РеквизитСправочникаА.РеквизитСправочникаБ;

Мы используем стандартное ПКО СправочникБ -> СправочникБ. Но в самом ПКО в обработчике Перед выгрузкой мы отключаем стандартные поля поиска и вручную конструируем XML-узел уникального идентификатора, подставляя туда GUID от СправочникаА:


// Код в обработчике "Перед выгрузкой" ПКО СправочникБ -> СправочникБ
// (Предварительно нужно передать ГУИД_А через ВходящиеДанные из документа)

УзелКоллекцииСвойств.ЗаписатьНачалоЭлемента("Свойство");
УстановитьАтрибут(УзелКоллекцииСвойств, "Имя", "{УникальныйИдентификатор}");
                    
Если НЕ ВыполнитьОбменДаннымиВОптимизированномФормате Тогда
    УстановитьАтрибут(УзелКоллекцииСвойств, "Тип", "Строка");
КонецЕсли;
                    
одЗаписатьЭлемент(УзелКоллекцииСвойств, "Значение", ГУИД_А);
УзелКоллекцииСвойств.ЗаписатьКонецЭлемента();

Важное предупреждение: Хотя этот способ рабочий, применять его в промышленной разработке крайне не рекомендуется. Он чувствителен к версии платформы, настройкам оптимизированного формата обмена КД и существенно усложняет чтение и отладку правил другими разработчиками.

Резюме

Мы рассмотрели три подхода к решению проблемы подмены GUID при конвертации данных. Проанализировав все плюсы и минусы, можно сделать вывод: Способ 1 (через обработчик «Поля поиска») является наиболее предпочтительным. Он сохраняет декларативную структуру правил КД 2.1, гарантирует отсутствие битых ссылок при загрузке документов и легко поддается отладке стандартными средствами платформы 1С.

← На главную