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

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

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

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

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

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

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

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

Глубина иерархии не ограничена жёстко, но типовые конфигурации обычно используют 3–7 уровней. Это значит, что простое обращение Элемент.Родитель.Родитель ненадёжно: число уровней заранее неизвестно, а лишний уровень обращения даст пустую ссылку или ошибку обращения к свойству пустого значения.

Способ 1: цикл по родителям до корня

Самый понятный и надёжный вариант — цикл Пока, который поднимается по цепочке родителей, пока не дойдёт до элемента без родителя. Он не зависит от глубины дерева и не рискует переполнением стека.

Функция ПолучитьВерхнегоРодителя(ЭлементСправочника) Экспорт

ТекущийРодитель = ЭлементСправочника.Родитель;

ВерхнийРодитель = ТекущийРодитель;

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

ВерхнийРодитель = ТекущийРодитель;

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

КонецЦикла;

Возврат ВерхнийРодитель;

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

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

1c
ВерхнийРодитель = ПолучитьВерхнегоРодителя(ТекущаяНоменклатура);
Если ЗначениеЗаполнено(ВерхнийРодитель) Тогда
    Сообщить(ВерхнийРодитель.Наименование);
КонецЕсли;

Способ 2: рекурсивная функция

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

Функция ВерхнийРодительРекурсивно(ЭлементСправочника) Экспорт

Если Не ЗначениеЗаполнено(ЭлементСправочника.Родитель) Тогда

Возврат ЭлементСправочника;

Иначе

Возврат ВерхнийРодительРекурсивно(ЭлементСправочника.Родитель);

КонецЕсли;

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

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

Способ 3: получение через запрос

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

ВЫБРАТЬ

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

Номенклатура.Родитель КАК Родитель,

Номенклатура.Родитель.Родитель КАК РодительВторогоУровня

ИЗ

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

Полностью «развернуть» произвольную глубину в одном запросе нельзя — число уровней в запросе фиксируется явно. Если глубина в вашей базе ограничена (например, не более трёх уровней), можно последовательно выбрать Родитель.Родитель.Родитель и взять первое непустое значение через ВЫБОР. Для неограниченной глубины проще выгрузить ссылки и родителей запросом, а обход выполнить в памяти через соответствие — так будет одно обращение к базе вместо множества.

Сравнение вариантов

Цикл Пока

Универсально, безопасно при любой глубине. Минус — обращение к базе на каждый уровень при работе через свойства.

Рекурсия

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

Запрос + обход в памяти

Оптимально для массовой обработки и отчётов: одно обращение к базе. Требует больше кода.

Оптимизация: как не замедлить отчёт

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

Правильный подход для массовой обработки: одним запросом выбрать все ссылки и всех их родителей (включая вышестоящие уровни), построить соответствие «ссылка → родитель» и дальше подниматься по дереву в памяти. Время работы перестаёт зависеть от количества элементов линейно по обращениям к СУБД.

Оптимальный порядок для массовой обработки
  1. 1
    Одним запросом выберите все нужные элементы и их родителей всех уровней
  2. 2
    Постройте соответствие: ключ — ссылка, значение — родитель
  3. 3
    Для каждого элемента поднимитесь по соответствию до пустого родителя
  4. 4
    Используйте найденный корень в дальнейшей логике или группировке отчёта

Частые ошибки и как их проверить

Первая типичная ошибка — обращение к Родитель у элемента справочника без иерархии или у объекта, где реквизит называется иначе. Вторая — отсутствие проверки на пустую ссылку перед чтением свойств: Элемент.Родитель.Наименование при пустом родителе вернёт пустую строку без ошибки, что маскирует проблему в логике.

Третья ошибка — зацикливание. Если в данных по какой-то причине образовалось кольцо (элемент ссылается сам на себя через цепочку родителей), цикл Пока станет бесконечным. В штатной работе платформа не даёт назначить элементу родителя из его собственных подчинённых, но при загрузках через обмены и обработки такое возможно. Для защиты добавьте счётчик итераций с разумным пределом.

Типичные ошибки
01
Обращение Элемент.Родитель.Родитель с фиксированным числом уровней — ломается при другой глубине дерева
02
Вызов функции в цикле по тысячам элементов без выгрузки в память — отчёт работает минутами
03
Отсутствие защиты от зацикливания при повреждённой иерархии — бесконечный цикл
04
Смешение поведения: одна функция возвращает пустую ссылку, другая — сам элемент, вызывающий код не готов к обоим случаям
Контрольные точки

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

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

Функция возвращает пустую ссылку или сам элемент — согласно заданному поведению

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

Ошибка обращения к свойству или зависание

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

Возвращается именно корневая группа, а не промежуточная

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

Возвращается ближайший родитель — значит, цикл не доходит до конца

Скорость на большом объёме
Норма

Обработка тысяч элементов занимает секунды

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

Каждый элемент обрабатывается заметное время — обращения к базе в цикле

FAQ

Как получить родителя определённого уровня, а не самого верхнего?

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

Работает ли свойство Родитель у справочника без иерархии?

Нет. Если в конфигураторе у справочника отключена иерархия, реквизита Родитель не существует, и обращение к нему вызовет ошибку. Проверить вид иерархии можно в свойствах справочника в конфигураторе на закладке «Иерархия».

Можно ли получить верхнего родителя в СКД без кода?

Частично. В запросе набора данных можно выбрать родителей фиксированного числа уровней через точку и собрать первое непустое значение конструкцией ВЫБОР. Для произвольной глубины иерархии без кода решения нет — используйте функцию в общем модуле и вычисляемое поле.

Что вернёт функция, если у элемента нет родителя?

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

Как защититься от бесконечного цикла при повреждённой иерархии?

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

Итог

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

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