К статье
Практический материал

Разработка и Конфигурация · 10 мин

Как получить всех родителей элемента справочника в 1С

Способы получить всех родителей элемента иерархического справочника 1С: запрос с ИТОГИ ПО ИЕРАРХИИ, В ИЕРАРХИИ, цикл по Родитель. Примеры кода и типичные ошибки.

Иерархические справочники в 1С хранят элементы в виде дерева: у каждого элемента есть ссылка на родителя, а у того — на своего. Задача «получить всех родителей элемента» возникает при построении полного пути к элементу, проверке принадлежности к группе на любом уровне вложенности, формировании отчётов и обменов. Платформа предлагает несколько подходов — от простого цикла по свойству Родитель до запросов с иерархическими итогами.

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

Как устроена иерархия справочника и свойство Родитель

В иерархическом справочнике у каждого элемента есть стандартный реквизит Родитель — ссылка на группу (или элемент, если иерархия «элементов»), в которую он входит. У элементов верхнего уровня родитель пустой. Цепочка ссылок Родитель → Родитель → Родитель … и есть полный путь элемента в дереве.

Код получения родителей в обоих случаях одинаков, но при обходе дерева в запросах вид иерархии влияет на структуру результата.

Глубина вложенности заранее неизвестна: в одном справочнике два уровня, в другом — десять. Поэтому любое решение должно работать в цикле или рекурсивно, а не фиксированным числом обращений.

Получение родителей циклом по ссылке Родитель

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

Функция ПолучитьВсехРодителей(Элемент)

Родители = Новый Массив;

ТекущийРодитель = Элемент.Родитель;

Пока ЗначениеЗаполнено(ТекущийРодитель) Цикл

Родители.Добавить(ТекущийРодитель);

ТекущийРодитель = ТекущийРодитель.Родитель;

КонецЦикла;

Возврат Родители;

КонецФункции

Массив заполняется от ближнего родителя к корню. Если нужен порядок «от корня к элементу», используйте Родители.Вставить(0, ТекущийРодитель) вместо Добавить.

Главный недостаток — производительность: каждое обращение ТекущийРодитель.Родитель через точку от ссылки вызывает обращение к базе данных. Для одного элемента это незаметно, но в цикле по тысячам элементов такой код приведёт к лавине запросов и заметному замедлению.

Проверка вхождения элемента в группу запросом В ИЕРАРХИИ

Частая практическая задача — узнать, входит ли элемент в заданную группу на любом уровне вложенности. Для этого в языке запросов есть оператор В ИЕРАРХИИ. Он возвращает истину, если элемент равен группе или находится в любой её подгруппе.

ВЫБРАТЬ

Номенклатура.Ссылка КАК Ссылка

ИЗ

Справочник.Номенклатура КАК Номенклатура

ГДЕ

Номенклатура.Ссылка В ИЕРАРХИИ(&Группа)

Обратная задача — получить для одного элемента все группы, в которые он входит, — решается инверсией условия: выбираем группы, для которых элемент находится в их иерархии.

ВЫБРАТЬ

Номенклатура.Ссылка КАК Группа

ИЗ

Справочник.Номенклатура КАК Номенклатура

ГДЕ

Номенклатура.ЭтоГруппа

И &Элемент В ИЕРАРХИИ(Номенклатура.Ссылка)

Такой запрос одним обращением к базе возвращает всех родителей элемента, что существенно быстрее цикла при массовой обработке. Условие ЭтоГруппа нужно только для справочников с иерархией групп и элементов; при иерархии элементов его следует убрать.

bsl
Запрос = Новый Запрос("ВЫБРАТЬ Группы.Ссылка ИЗ Справочник.Номенклатура КАК Группы ГДЕ Группы.ЭтоГруппа И &Элемент В ИЕРАРХИИ(Группы.Ссылка)");
Запрос.УстановитьПараметр("Элемент", СсылкаНаЭлемент);
Родители = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");

Построение дерева и иерархические итоги запросом

Когда нужно получить родителей сразу для множества элементов или построить полное дерево справочника, используют итоги по иерархии. Конструкция ИТОГИ ПО Ссылка ТОЛЬКО ИЕРАРХИЯ возвращает результат в виде дерева, которое обходится через Выборка.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией).

Альтернативный приём — рекурсивное соединение таблицы справочника самой с собой по условию Таблица.Родитель = Таблица1.Ссылка. Он работает только при заранее известной глубине вложенности, поэтому на практике применяется редко: число соединений должно покрывать максимальный уровень дерева.

Для большинства задач достаточно связки двух запросов: первый выбирает нужные элементы, второй по параметру-массиву элементов возвращает их родителей через В ИЕРАРХИИ в обратную сторону, как показано в предыдущем разделе. Это даёт плоскую таблицу «элемент — все его группы», удобную для дальнейшей обработки.

Сравнение способов получения родителей

Цикл по Родитель

Подходит для одного элемента и разовых вызовов. Прост, но генерирует обращение к базе на каждый уровень иерархии.

Запрос В ИЕРАРХИИ

Оптимален для проверки вхождения в группу и получения всех групп элемента. Одно обращение к СУБД, работает с любой глубиной.

ИТОГИ ПО.. ИЕРАРХИЯ

Нужен для построения дерева и обхода иерархии целиком. Сложнее в обработке результата, избыточен для одиночных проверок.

Пошаговый сценарий: построить полный путь к элементу

Разберём прикладную задачу: сформировать строку вида «Корневая группа / Подгруппа / Элемент» для вывода в печатную форму или обмен. Порядок действий одинаков в любой конфигурации.

Порядок действий
  1. 1
    Проверьте, что справочник иерархический и у элемента заполнен Родитель (иначе путь состоит из самого элемента).
  2. 2
    Получите массив родителей циклом по свойству Родитель или запросом В ИЕРАРХИИ.
  3. 3
    Разверните массив, чтобы первым шёл корневой родитель.
  4. 4
    Соберите строку через Разделитель, например СтрСоединить(Части, " / ").
  5. 5
    Проверьте результат на элементе верхнего уровня: путь должен содержать только его наименование.
Функция ПолныйПуть(Элемент)

Части = Новый Массив;

Части.Добавить(Строка(Элемент));

ТекущийРодитель = Элемент.Родитель;

Пока ЗначениеЗаполнено(ТекущийРодитель) Цикл

Части.Вставить(0, Строка(ТекущийРодитель));

ТекущийРодитель = ТекущийРодитель.Родитель;

КонецЦикла;

Возврат СтрСоединить(Части, " / ");

КонецФункции

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

Как проверить результат и где чаще всего ошибаются

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

Контрольные точки

Как проверить результат

Элемент верхнего уровня
Норма

Список родителей пуст, путь равен наименованию элемента

Тревожный признак

Ошибка обращения к Родитель или лишняя пустая строка в пути

Элемент глубокого уровня
Норма

Все группы цепочки присутствуют, порядок от корня к элементу

Тревожный признак

Пропущены промежуточные группы или порядок перевёрнут

Запрос В ИЕРАРХИИ
Норма

Возвращает только группы, реально содержащие элемент

Тревожный признак

В результат попадают лишние группы — проверьте направление условия

Типичные ошибки
01
Перепутано направление В ИЕРАРХИИ: вместо «элемент В ИЕРАРХИИ(группа)» написано «группа В ИЕРАРХИИ(элемент)» — результат пустой или неверный.
02
Цикл по Родитель без проверки ЗначениеЗаполнено — обращение к реквизиту пустой ссылки и ошибка выполнения.
03
Чтение Родителя через точку в цикле по тысячам элементов — резкое падение производительности из-за обращений к СУБД.
04
Игнорирование вида иерархии: условие ЭтоГруппа применено к справочнику с иерархией элементов, где такого смысла у отбора нет.
05
Ожидание фиксированной глубины дерева — код ломается, когда пользователи добавляют новый уровень вложенности.

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

В типовых конфигурациях для проверки вхождения в группу часто есть готовые функции общих модулей (например, проверки принадлежности номенклатуры группе). Перед написанием своего кода посмотрите существующие общие модули — переиспользование типового кода упрощает обновление конфигурации.
ПЗ
Практическое замечание

Частые вопросы

Как получить только родителя верхнего уровня (корневую группу)?

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

Работает ли В ИЕРАРХИИ с массивом групп?

Да. В параметр можно передать массив или список значений групп: условие «элемент В ИЕРАРХИИ(&Группы)» будет истинно, если элемент входит хотя бы в одну из перечисленных групп. Это удобно для отборов по нескольким веткам дерева.

Как получить родителей в запросе без временных таблиц для множества элементов?

Соедините таблицу элементов с таблицей групп по условию «элемент В ИЕРАРХИИ(группа.Ссылка)». Запрос вернёт пары «элемент — группа-родитель» для всех элементов одним обращением к базе. Сгруппируйте результат по элементу при необходимости.

Что вернёт свойство Родитель у элемента верхнего уровня?

Пустую ссылку соответствующего типа справочника. Поэтому перед чтением реквизитов родителя всегда проверяйте его через ЗначениеЗаполнено() или сравнение с пустой ссылкой, иначе получите ошибку обращения к данным.

Можно ли получить родителей через СКД?

Да. В наборе данных СКД используется тот же язык запросов: оператор В ИЕРАРХИИ в параметрах и иерархические итоги в настройках группировок. Для вывода дерева в отчёте достаточно добавить группировку по полю ссылки с типом иерархии «Иерархия».

Есть ли ограничение на глубину иерархии справочника?

Жёсткого прикладного ограничения глубины в платформе нет, но очень глубокие деревья замедляют иерархические запросы и неудобны пользователям. На практике стараются держать разумное число уровней и контролировать структуру регламентно.

Итог

Что важно запомнить

Для одного элемента родителей получают циклом по свойству Родитель до пустой ссылки. Для проверки вхождения в группу и массовой обработки используйте запрос с оператором В ИЕРАРХИИ — он работает с любой глубиной за одно обращение к базе. Всегда проверяйте заполненность родителя и учитывайте вид иерархии справочника.