Разработка и Конфигурация · 10 мин
Как получить всех родителей элемента справочника в 1С
Способы получить всех родителей элемента иерархического справочника 1С: запрос с ИТОГИ ПО ИЕРАРХИИ, В ИЕРАРХИИ, цикл по Родитель. Примеры кода и типичные ошибки.
Иерархические справочники в 1С хранят элементы в виде дерева: у каждого элемента есть ссылка на родителя, а у того — на своего. Задача «получить всех родителей элемента» возникает при построении полного пути к элементу, проверке принадлежности к группе на любом уровне вложенности, формировании отчётов и обменов. Платформа предлагает несколько подходов — от простого цикла по свойству Родитель до запросов с иерархическими итогами.
Выбор способа зависит от контекста: сколько элементов нужно обработать, где выполняется код (запрос или встроенный язык) и нужна ли вся цепочка родителей или только проверка вхождения в конкретную группу. Ниже разобраны рабочие варианты с примерами кода, их ограничения и типичные ошибки.
Как устроена иерархия справочника и свойство Родитель
В иерархическом справочнике у каждого элемента есть стандартный реквизит Родитель — ссылка на группу (или элемент, если иерархия «элементов»), в которую он входит. У элементов верхнего уровня родитель пустой. Цепочка ссылок Родитель → Родитель → Родитель … и есть полный путь элемента в дереве.
Код получения родителей в обоих случаях одинаков, но при обходе дерева в запросах вид иерархии влияет на структуру результата.
Глубина вложенности заранее неизвестна: в одном справочнике два уровня, в другом — десять. Поэтому любое решение должно работать в цикле или рекурсивно, а не фиксированным числом обращений.
Получение родителей циклом по ссылке Родитель
Самый простой способ — последовательно читать свойство Родитель, пока не будет достигнута пустая ссылка. Способ подходит для разовой обработки одного элемента, например при построении строки полного наименования.
Функция ПолучитьВсехРодителей(Элемент)
Родители = Новый Массив;
ТекущийРодитель = Элемент.Родитель;
Пока ЗначениеЗаполнено(ТекущийРодитель) Цикл
Родители.Добавить(ТекущийРодитель);
ТекущийРодитель = ТекущийРодитель.Родитель;
КонецЦикла;
Возврат Родители;
КонецФункции
Массив заполняется от ближнего родителя к корню. Если нужен порядок «от корня к элементу», используйте Родители.Вставить(0, ТекущийРодитель) вместо Добавить.
Главный недостаток — производительность: каждое обращение ТекущийРодитель.Родитель через точку от ссылки вызывает обращение к базе данных. Для одного элемента это незаметно, но в цикле по тысячам элементов такой код приведёт к лавине запросов и заметному замедлению.
Проверка вхождения элемента в группу запросом В ИЕРАРХИИ
Частая практическая задача — узнать, входит ли элемент в заданную группу на любом уровне вложенности. Для этого в языке запросов есть оператор В ИЕРАРХИИ. Он возвращает истину, если элемент равен группе или находится в любой её подгруппе.
ВЫБРАТЬ
Номенклатура.Ссылка КАК Ссылка
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
Номенклатура.Ссылка В ИЕРАРХИИ(&Группа)
Обратная задача — получить для одного элемента все группы, в которые он входит, — решается инверсией условия: выбираем группы, для которых элемент находится в их иерархии.
ВЫБРАТЬ
Номенклатура.Ссылка КАК Группа
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
Номенклатура.ЭтоГруппа
И &Элемент В ИЕРАРХИИ(Номенклатура.Ссылка)
Такой запрос одним обращением к базе возвращает всех родителей элемента, что существенно быстрее цикла при массовой обработке. Условие ЭтоГруппа нужно только для справочников с иерархией групп и элементов; при иерархии элементов его следует убрать.
Запрос = Новый Запрос("ВЫБРАТЬ Группы.Ссылка ИЗ Справочник.Номенклатура КАК Группы ГДЕ Группы.ЭтоГруппа И &Элемент В ИЕРАРХИИ(Группы.Ссылка)");
Запрос.УстановитьПараметр("Элемент", СсылкаНаЭлемент);
Родители = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");Построение дерева и иерархические итоги запросом
Когда нужно получить родителей сразу для множества элементов или построить полное дерево справочника, используют итоги по иерархии. Конструкция ИТОГИ ПО Ссылка ТОЛЬКО ИЕРАРХИЯ возвращает результат в виде дерева, которое обходится через Выборка.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией).
Альтернативный приём — рекурсивное соединение таблицы справочника самой с собой по условию Таблица.Родитель = Таблица1.Ссылка. Он работает только при заранее известной глубине вложенности, поэтому на практике применяется редко: число соединений должно покрывать максимальный уровень дерева.
Для большинства задач достаточно связки двух запросов: первый выбирает нужные элементы, второй по параметру-массиву элементов возвращает их родителей через В ИЕРАРХИИ в обратную сторону, как показано в предыдущем разделе. Это даёт плоскую таблицу «элемент — все его группы», удобную для дальнейшей обработки.
Сравнение способов получения родителей
Подходит для одного элемента и разовых вызовов. Прост, но генерирует обращение к базе на каждый уровень иерархии.
Оптимален для проверки вхождения в группу и получения всех групп элемента. Одно обращение к СУБД, работает с любой глубиной.
Нужен для построения дерева и обхода иерархии целиком. Сложнее в обработке результата, избыточен для одиночных проверок.
Пошаговый сценарий: построить полный путь к элементу
Разберём прикладную задачу: сформировать строку вида «Корневая группа / Подгруппа / Элемент» для вывода в печатную форму или обмен. Порядок действий одинаков в любой конфигурации.
- 1Проверьте, что справочник иерархический и у элемента заполнен Родитель (иначе путь состоит из самого элемента).
- 2Получите массив родителей циклом по свойству Родитель или запросом В ИЕРАРХИИ.
- 3Разверните массив, чтобы первым шёл корневой родитель.
- 4Соберите строку через Разделитель, например СтрСоединить(Части, " / ").
- 5Проверьте результат на элементе верхнего уровня: путь должен содержать только его наименование.
Функция ПолныйПуть(Элемент)
Части = Новый Массив;
Части.Добавить(Строка(Элемент));
ТекущийРодитель = Элемент.Родитель;
Пока ЗначениеЗаполнено(ТекущийРодитель) Цикл
Части.Вставить(0, Строка(ТекущийРодитель));
ТекущийРодитель = ТекущийРодитель.Родитель;
КонецЦикла;
Возврат СтрСоединить(Части, " / ");
КонецФункции
Функция устойчива к любой глубине дерева и корректно отрабатывает на элементах верхнего уровня: цикл просто не выполнится ни разу.
Как проверить результат и где чаще всего ошибаются
После реализации полезно прогнать код на контрольных примерах: элемент верхнего уровня (родителей нет), элемент на втором уровне (один родитель) и элемент на максимальной глубине. Все три случая должны давать ожидаемый результат без ошибок.
Как проверить результат
Список родителей пуст, путь равен наименованию элемента
Ошибка обращения к Родитель или лишняя пустая строка в пути
Все группы цепочки присутствуют, порядок от корня к элементу
Пропущены промежуточные группы или порядок перевёрнут
Возвращает только группы, реально содержащие элемент
В результат попадают лишние группы — проверьте направление условия
Отдельного внимания заслуживает кеширование: если родители нужны многократно в рамках одной операции, получите их один раз запросом и держите в соответствии «элемент — массив родителей». Это стандартный приём оптимизации при обменах и отчётах.
В типовых конфигурациях для проверки вхождения в группу часто есть готовые функции общих модулей (например, проверки принадлежности номенклатуры группе). Перед написанием своего кода посмотрите существующие общие модули — переиспользование типового кода упрощает обновление конфигурации.
Частые вопросы
Как получить только родителя верхнего уровня (корневую группу)?
Пройдите циклом по свойству Родитель до конца цепочки и возьмите последнее непустое значение. Запросом это делается выборкой групп, у которых Родитель пуст, с условием, что элемент находится в их иерархии.
Работает ли В ИЕРАРХИИ с массивом групп?
Да. В параметр можно передать массив или список значений групп: условие «элемент В ИЕРАРХИИ(&Группы)» будет истинно, если элемент входит хотя бы в одну из перечисленных групп. Это удобно для отборов по нескольким веткам дерева.
Как получить родителей в запросе без временных таблиц для множества элементов?
Соедините таблицу элементов с таблицей групп по условию «элемент В ИЕРАРХИИ(группа.Ссылка)». Запрос вернёт пары «элемент — группа-родитель» для всех элементов одним обращением к базе. Сгруппируйте результат по элементу при необходимости.
Что вернёт свойство Родитель у элемента верхнего уровня?
Пустую ссылку соответствующего типа справочника. Поэтому перед чтением реквизитов родителя всегда проверяйте его через ЗначениеЗаполнено() или сравнение с пустой ссылкой, иначе получите ошибку обращения к данным.
Можно ли получить родителей через СКД?
Да. В наборе данных СКД используется тот же язык запросов: оператор В ИЕРАРХИИ в параметрах и иерархические итоги в настройках группировок. Для вывода дерева в отчёте достаточно добавить группировку по полю ссылки с типом иерархии «Иерархия».
Есть ли ограничение на глубину иерархии справочника?
Жёсткого прикладного ограничения глубины в платформе нет, но очень глубокие деревья замедляют иерархические запросы и неудобны пользователям. На практике стараются держать разумное число уровней и контролировать структуру регламентно.
Что важно запомнить
Для одного элемента родителей получают циклом по свойству Родитель до пустой ссылки. Для проверки вхождения в группу и массовой обработки используйте запрос с оператором В ИЕРАРХИИ — он работает с любой глубиной за одно обращение к базе. Всегда проверяйте заполненность родителя и учитывайте вид иерархии справочника.