Почему при обмене через КД 2.0 не переносится верхняя иерархия (родители родителей) и как это исправить?

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

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

В этой статье мы подробно разберем, почему так происходит в «Конвертации данных 2.0» (КД 2.0), как работает механизм выгрузки ссылок и какое простое изменение в правилах поможет восстановить полную структуру дерева групп.

Суть проблемы: разрыв цепочки иерархии

Давайте проанализируем ситуацию, описанную в исходной задаче. У нас есть иерархический справочник в базе-источнике. Мы хотим перенести его в базу-приемник, при этом разделяя данные на два разных справочника:

  1. Сами элементы (например, конкретные стройки) попадают в справочник Проекты.
  2. Группы (папки, объединяющие стройки) попадают в справочник Папки проектов.

При стандартной настройке правил конвертации объектов (ПКО) мы видим следующую картину: элемент создается, его непосредственная папка (Родитель) создается, но если у этой папки есть своя родительская папка (уровень выше), она в приемник не попадает. Свойство Родитель у папки остается пустым или содержит ссылку на объект, который не был создан ("Объект не найден"). Для детальной проверки выгружаемых ссылок и свойств можно использовать инструмент для анализа состава файла выгрузки.

Как работает оптимизация выгрузки в КД 2.0

Чтобы понять решение, нам нужно разобраться во внутренней логике обработки выгрузки. Платформа старается минимизировать объем передаваемых данных и избежать зацикливания (когда объект ссылается сам на себя или на другой объект, который ссылается обратно).

Когда система выгружает объект (назовем его «Проект А»), она доходит до его свойства Родитель (назовем его «Папка 1»). Система видит, что это ссылочное поле. Стандартное поведение КД 2.0 в этом случае таково:

  1. Система проверяет, был ли объект «Папка 1» уже выгружен ранее полностью.
  2. Если нет, то система инициирует выгрузку «Папки 1», но включает специальный режим оптимизации: Только ссылка.

В коде обработчиков это соответствует системному параметру ТолькоПолучитьУзелСсылки, который устанавливается в значение Истина.

Что это значит для нас?
В режиме «Только ссылка» система формирует XML-узел, содержащий уникальный идентификатор (GUID) объекта и его поля поиска. Но она не идет вглубь свойств этого объекта. То есть, выгрузив ссылку на «Папку 1», система не смотрит, кто является родителем «Папки 1». Цепочка обрывается. Рекурсия не запускается.

Именно поэтому мы видим только один уровень вверх: Элемент -> Родитель. А связь Родитель -> Дедушка отсутствует, потому что «Родитель» выгрузился «облегченным» способом.

Решение: принудительная полная выгрузка

Чтобы заставить систему «размотать» всю цепочку иерархии до самого корня, нам нужно отключить оптимизацию для правил конвертации папок. Мы должны сказать системе: «Когда ты выгружаешь папку, даже если это делается просто для заполнения ссылки в дочернем элементе, выгружай ее полностью, со всеми свойствами».

Для этого в правилах обмена (в конфигурации «Конвертация данных») необходимо использовать параметр ТолькоПолучитьУзелСсылки.

Рассмотрим пошагово, как это сделать:

  1. Откройте ваши правила обмена.
  2. Найдите Правило Конвертации Объектов (ПКО), которое отвечает за выгрузку иерархической части (в нашем примере это ПКО для справочника Папки проектов или того справочника, который выступает в роли родителя).
  3. Перейдите на вкладку Обработчики событий.
  4. Выберите обработчик Перед выгрузкой (BeforeExport).
  5. Напишите следующий код:

// Принудительно выгружаем объект целиком, а не только его ссылку.
// Это заставит систему обработать свойства этого объекта, включая его Родителя.
ТолькоПолучитьУзелСсылки = Ложь;

Почему это работает?

Когда мы устанавливаем ТолькоПолучитьУзелСсылки = Ложь, мы меняем сценарий:

  1. Выгружается «Проект А».
  2. Доходим до свойства Родитель -> «Папка 1».
  3. Система переходит к выгрузке «Папки 1» по соответствующему ПКО.
  4. Благодаря нашему коду, флаг оптимизации снимается. «Папка 1» выгружается полностью.
  5. Система начинает перебирать свойства «Папки 1» (Правила конвертации свойств - ПКС).
  6. Среди свойств «Папки 1» есть свойство Родитель, которое указывает на «Папку 2» (дедушку).
  7. Так как «Папка 1» выгружается полностью, система обязана выгрузить и ее свойства. Она переходит к выгрузке «Папки 2».
  8. Для «Папки 2» работает то же самое ПКО, где снова срабатывает наш код.
  9. Процесс повторяется рекурсивно, пока не будет достигнут корень иерархии (пустой родитель).

Особенности реализации при разделении справочников

В рассматриваемом примере задача усложняется тем, что один справочник-источник («Объекты строительства») делится на два справочника-приемника. Давайте структурируем правильный подход к такой настройке.

Нам понадобятся два ПКО для одного источника:

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

Важный нюанс: Если ваш целевой справочник «Папки проектов» имеет вид иерархии «Иерархия элементов» (а не групп и элементов), то свойство ЭтоГруппа у него может отсутствовать или быть ложным. В этом случае отбор объектов для выгрузки нужно строить аккуратно, чтобы обычные проекты не попали в папки и наоборот.

Возможные побочные эффекты и производительность

Использование флага ТолькоПолучитьУзелСсылки = Ложь — мощный инструмент, но его нужно применять осознанно. Рассмотрим последствия:

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

2. Увеличение объема файла обмена
В файл XML будет попадать полная структура папок. Это необходимо для создания иерархии, так что это неизбежная плата за результат.

3. Риск зацикливания
Если в вашей структуре данных есть циклические ссылки (Папка А -> Папка Б -> Папка А), то отключение контроля ссылок приведет к бесконечной рекурсии и падению 1С с переполнением стека. Убедитесь, что в иерархии справочника нет циклов.

Альтернативный подход (программная выгрузка)

Если по каким-то причинам глобальное отключение оптимизации вам не подходит, можно воспользоваться методом ВыгрузитьПоПравилу(). Этот код можно разместить в обработчике ПослеВыгрузки элемента.

Пример логики:


Если ЗначениеЗаполнено(Источник.Родитель) Тогда
    // Принудительно вызываем выгрузку родителя по нужному правилу
    ВыгрузитьПоПравилу(Источник.Родитель, , , , "ПКО_ПапкиПроектов");
КонецЕсли;

Этот метод дает больше контроля, но часто требует более сложной отладки параметров. Метод с флагом ТолькоПолучитьУзелСсылки = Ложь является более штатным и простым решением для восстановления иерархии.

Резюме

Если при обмене данными вы видите, что создается только непосредственный родитель, а вышестоящие уровни теряются:

  1. Найдите ПКО, отвечающее за выгрузку родительского объекта (группы/папки).
  2. В обработчике Перед выгрузкой этого ПКО пропишите ТолькоПолучитьУзелСсылки = Ложь;.
  3. Убедитесь, что в ПКС свойства Родитель у этого ПКО указано правило конвертации, ссылающееся на это же ПКО (рекурсивный вызов).

Это обеспечит корректную передачу всей структуры дерева справочника из базы-источника в базу-приемник.

← На главную