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