Как в Конвертации данных 2.1 настроить поиск по GUID при расщеплении одного документа на несколько и избежать дублей?

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

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

Разберем детально причины такого поведения механизмов платформы и по шагам рассмотрим корректные способы решения этой задачи.

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

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

  1. Нестабильный расчет детерминированного GUID. Если при расчете идентификатора для дочерних документов используется хеш от состава строк, номеров строк или сумм, то любое добавление новой строки в табличную часть или сдвиг строк меняет результирующий GUID. В этом случае поиск по старому идентификатору не срабатывает, и система вполне закономерно создает новый документ.
  2. Объект в базе-приемнике сохраняется со случайным GUID платформы. При создании нового документа методом СоздатьДокумент() платформа 1С всегда генерирует для него новый уникальный идентификатор. Если при загрузке для нового объекта явно не был вызван платформенный метод УстановитьСсылкуНового(), документ запишется в базу не с тем GUID, который был передан из источника. При повторном обмене поиск по вычисленному GUID завершится неудачей, так как в базе документа с таким идентификатором нет.
  3. Некорректная ручная запись тегов в XML-поток. Попытка внедрить служебный узел {УникальныйИдентификатор} напрямую в обработчике «Перед выгрузкой» ПКС через прямое манипулирование объектом УзелКоллекцииСвойств с установкой флага Отказ = Истина нарушает штатный сбор полей поиска в КД 2.1. Если выгрузка идет в неоптимизированном режиме или нарушается логика стандартного чтения, узел поиска игнорируется.

Способ 1. Корректный перенос идентификатора через параметры и метод УстановитьСсылкуНового

Рассмотрим правильный подход, исключающий прямое вмешательство в XML-поток. Передадим сгенерированный GUID через структуру параметров и явно обработаем его в правилах конвертации объектов (ПКО).

Посмотрим на логику выгрузки в ПВД («Перед обработкой»):


Для Каждого Документ Из МассивДокументов.СписокДокументов Цикл
    ВходящиеДанные = Новый Структура;
    ВходящиеДанные.Вставить("ИдентификаторОбъекта", Документ.guid);
    
    ВыгрузитьПоПравилу(Документ, , ВходящиеДанные, , "схПереводЖивотных2");
КонецЦикла;

В ПКО соответствующего документа в обработчике «Поля поиска» реализуем поиск существующего документа по полученному GUID:


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

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


Если Объект.ЭтоНовый() И ЗначениеЗаполнено(СсылкаНаОбъект) Тогда
    Объект.УстановитьСсылкуНового(СсылкаНаОбъект);
КонецЕсли;

Важное ограничение: метод УстановитьСсылкуНового() работает исключительно для еще не записанных объектов, когда вызов Объект.ЭтоНовый() возвращает Истина. Изменить GUID у существующего документа в базе невозможно.

Способ 2. Поиск по служебному строковому реквизиту

Если нет жесткого требования, чтобы сам идентификатор ссылки Ссылка.УникальныйИдентификатор() совпадал с расчетным значением, разберем более надежную архитектуру без подмены платформенных ссылок.

  1. Добавим в документ базы-приемника реквизит ИдентификаторСинхронизации (тип Строка, длина 100, индексируемый).
  2. При формировании строки или структуры в выгрузке заполняем это поле стабильным составным ключом (например: Строка(ДокументИсточник.УникальныйИдентификатор()) + "_" + ЗначениеКлючаГруппировки).
  3. В правиле ПКС для свойства ИдентификаторСинхронизации устанавливаем флаг «Поиск объекта при загрузке по свойству».
  4. В настройках ПКО отключаем флаг «Искать объект приемника по внутреннему идентификатору».

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

Правила формирования детерминированного GUID

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

  1. Не использовать динамические свойства строк. Нельзя включать в хеш номер строки (НомерСтроки), так как вставка строки в середину документа сместит индексы всех последующих строк и сломает сопоставление.
  2. Использовать устойчивые бизнес-ключи. Хеш должен строиться только на основании GUID исходного документа и постоянных аналитических признаков расщепления (например, идентификатора фермы, склада или стабильного уникального идентификатора строки табличной части).
← На главную