Как в КД2 не создавать иерархию (родителя), если элемент уже найден в приемнике?

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

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

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

Почему создаются лишние папки: особенности архитектуры КД2

Основная проблема при файловом обмене в КД2 заключается в том, что база-источник на момент выгрузки не знает, будет ли найден объект в базе-приемнике. Из-за архитектуры системы ссылочные объекты (в нашем случае реквизит Родитель) выгружаются в XML-файл до того, как выгрузится сам основной элемент.

Когда база-приемник начинает чтение XML-файла, она сначала встречает узлы с папками, добросовестно их создает, и только потом доходит до самого элемента. На этом этапе система понимает, что элемент существует (срабатывает флаг ОбъектНайден = Истина) и отменяет обновление его реквизитов. Но папки уже созданы в корне справочника, и откатить их создание стандартными средствами не получится. Выясним, как это можно обойти.

Способ 1: Передача иерархии через параметры объекта (Оптимально для XML-обмена)

Этот метод является самым надежным для файлового обмена. Его суть заключается в том, чтобы вообще отказаться от стандартной выгрузки реквизита Родитель и перенести ответственность за создание папок на момент после загрузки элемента, когда статус объекта уже точно известен.

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

  1. Откроем правила конвертации свойств (ПКС) для Номенклатуры и отключим стандартную выгрузку реквизита Родитель (снимаем флаг выгрузки).
  2. В правилах конвертации объектов (ПКО) элемента номенклатуры перейдем в обработчик «Перед выгрузкой». Здесь мы поместим данные родителя в исходящие параметры:

// Передаем наименование родителя или другие ключевые поля для поиска
ИсходящиеДанные.Вставить("ИмяРодителя", Источник.Родитель.Наименование);
// Можно передать Артикул родителя, если он есть, для более точного поиска
  1. Далее в этом же ПКО перейдем в обработчик «После загрузки». Напишем алгоритм, который программно найдет или создаст папку только в том случае, если мы загружаем новый элемент:

Если НЕ ОбъектНайден Тогда
    // Объект новый, значит папки нужны.
    ИмяПапки = ПараметрыОбъекта.Получить("ИмяРодителя");
    
    Если ЗначениеЗаполнено(ИмяПапки) Тогда
        НайденнаяПапка = Справочники.Номенклатура.НайтиПоНаименованию(ИмяПапки, Истина);
        
        Если НайденнаяПапка.Пустая() Тогда
            // Создаем новую группу программно
            НоваяГруппа = Справочники.Номенклатура.СоздатьГруппу();
            НоваяГруппа.Наименование = ИмяПапки;
            НоваяГруппа.Записать();
            НайденнаяПапка = НоваяГруппа.Ссылка;
        КонецЕсли;
        
        // Присваиваем родителя новому элементу
        Объект.Родитель = НайденнаяПапка;
    КонецЕсли;
КонецЕсли;

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

Способ 2: Разделение ПКО для элементов и групп

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

Посмотрим на алгоритм реализации:

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

// Отказываемся от выгрузки, если текущий объект - это папка
Отказ = Источник.ЭтоГруппа;
  1. Создаем второе ПКО для выгрузки только папок (групп). В его обработчике ПриВыгрузке пишем обратное условие:

// Отказываемся от выгрузки, если текущий объект - обычный элемент
Отказ = НЕ Источник.ЭтоГруппа;

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

Способ 3: Прямое COM-соединение

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

Проанализируем пример кода для обработчика «Перед выгрузкой» ПКО Номенклатуры:


// Проверяем наличие номенклатуры в базе-приемнике
НайденнаяНоменклатура = БазаПриемник.Справочники.Номенклатура.НайтиПоРеквизиту("Артикул", Источник.Артикул);

Если НайденнаяНоменклатура <> БазаПриемник.Справочники.Номенклатура.ПустаяСсылка() Тогда
    // Объект в приемнике уже есть. 
    // Отменяем выгрузку реквизита Родитель для данного элемента.
    УзелСсылки.Очистить(); // Либо снимаем флаги выгрузки конкретных ПКС
КонецЕсли;

Этот способ идеален для On-line обменов, так как позволяет экономить трафик и время, отсекая ненужные объекты до начала формирования пакета.

Способ 4: Использование стандартных флагов КД2

Рассмотрим менее гибкий, но быстрый вариант — использование штатных настроек ПКО. Для реквизита можно установить флаг «Не выгружать объекты свойств источника по ссылкам». При такой настройке КД2 выгрузит только поля поиска папки-родителя, но не станет тянуть весь объект группы со всеми ее реквизитами.

Чтобы база-приемник не плодила пустые ссылки-заглушки для ненайденных папок, в ПКО самой группы номенклатуры необходимо установить флаг «При переносе объекта по ссылке НЕ создавать новый объект, а только переносить ссылку».

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

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

← На главную