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

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

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

Как получить родителя и верхнего родителя элемента иерархического справочника в 1С: свойство Родитель, запросы с ИЕРАРХИЯ, рекурсия, примеры кода и типичные ошибки.

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

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

Ниже разобраны рабочие методы: свойство Родитель, цикл подъёма по иерархии, запрос с конструкцией В ИЕРАРХИИ, получение всех родителей через соединение таблицы с самой собой, а также типичные ошибки и способы проверки результата.

Что такое родитель и верхний родитель в иерархии 1С

Иерархический справочник в 1С хранит связь «элемент — группа» в системном поле Родитель (Parent). У каждого элемента есть не более одного родителя; у элементов верхнего уровня родитель пустой — это пустая ссылка соответствующего типа справочника.

Верхним (корневым) родителем обычно называют группу первого уровня, внутри которой на любой глубине находится элемент. Например, в цепочке «Товары → Электроника → Ноутбуки → Ноутбук X» непосредственный родитель элемента — «Ноутбуки», а верхний родитель — «Электроника» или «Товары», в зависимости от того, что считать корнем (верхний уровень вообще или первый уровень внутри заданной ветки).

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

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

Самый простой случай — у вас есть ссылка на элемент, и нужен его непосредственный родитель. Если работаете с объектом (открытая форма, обработка заполнения), свойство доступно напрямую:

РодительЭлемента = ЭлементОбъект.Родитель;

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

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

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

|ИЗ

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

|ГДЕ

| Номенклатура.Ссылка = &Ссылка";

Запрос.УстановитьПараметр("Ссылка", ТекущийЭлемент);

Выборка = Запрос.Выполнить().Выбрать();

Если Выборка.Следующий() Тогда

РодительЭлемента = Выборка.Родитель;

КонецЕсли;

Проверить, есть ли родитель вообще, помогает функция ЗначениеЗаполнено() или сравнение с пустой ссылкой: РодительЭлемента = Справочники.Номенклатура.ПустаяСсылка(). Для элемента верхнего уровня оба условия дадут «истину» — родителя нет.

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

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

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

Текущий = СсылкаНаЭлемент;

ВерхнийРодитель = СсылкаНаЭлемент;

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

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

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

КонецЦикла;

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

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

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

Альтернатива циклу — рекурсия:

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

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

Возврат СсылкаНаЭлемент;

КонецЕсли;

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

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

Рекурсия короче, но при глубокой иерархии упирается в ограничение стека вызовов и сложнее отлаживается. На практике глубина справочников редко превышает 5–10 уровней, поэтому оба варианта работоспособны; цикл предпочтительнее из-за контроля итераций.

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

Язык запросов 1С не имеет встроенной функции «верхний родитель», но позволяет решить задачу двумя способами: через оператор В ИЕРАРХИИ и через последовательное соединение таблицы справочника с самой собой.

Отбор элементов внутри ветки через В ИЕРАРХИИ

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

ВЫБРАТЬ

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

ИЗ

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

ГДЕ

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

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

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

Подъём к корню через самосоединение таблицы

Чтобы одним запросом получить родителей нескольких уровней, соедините таблицу справочника с собой нужное число раз:

ВЫБРАТЬ

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

Товары.Родитель КАК Родитель1,

Уровень2.Родитель КАК Родитель2,

Уровень3.Родитель КАК Родитель3

ИЗ

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

ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Уровень2

ПО Товары.Родитель = Уровень2.Ссылка

ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Уровень3

ПО Уровень2.Родитель = Уровень3.Ссылка

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

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

Свойство Родитель

Подходит для одиночного элемента и непосредственного родителя; для верхнего требует цикла и множества обращений к базе

Цикл подъёма по цепочке

Универсален для любой глубины; медленный при массовой обработке из-за обращений к БД на каждый уровень

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

Оптимален для отбора всех потомков ветки в отчётах; не возвращает цепочку родителей конкретного элемента

Самосоединение таблицы

Один запрос для множества элементов; требует заранее знать максимальную глубину иерархии

Как выбрать способ под конкретную задачу

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

Маршрут решения

Как выбрать действие

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

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

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

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

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

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

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

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

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

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

Элемент на глубине 3–5 уровней
Норма

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

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

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

Пакетная обработка 1000 элементов
Норма

Выполняется за приемлемое время без тысяч отдельных запросов к БД

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

Заметные паузы, рост числа обращений к СУБД

Помеченные на удаление группы в цепочке
Норма

Поведение определено явно (учитывать или пропускать)

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

Алгоритм молча возвращает помеченную группу как корень

Типичные ошибки
01
Обращение к Родитель у пустой ссылки — приводит к ошибке; всегда проверяйте ЗначениеЗаполнено перед подъёмом на следующий уровень
02
Цикл без ограничителя итераций — при зацикленных ссылках в данных даёт зависание сеанса
03
Использование разыменования ссылки в цикле по тысячам элементов — резкое падение производительности; заменяйте запросом
04
Путаница между В ИЕРАРХИИ и простым сравнением с Родитель — сравнение с одной группой не захватывает вложенные подгруппы
05
Игнорирование вида иерархии справочника — в иерархии элементов родителем может быть не группа, и проверка ЭтоГруппа даст неверный фильтр

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

Итог

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

Непосредственный родитель — свойство Родитель. Верхний родитель — цикл подъёма до пустой ссылки или запрос с самосоединением; для отбора потомков ветки — оператор В ИЕРАРХИИ. Защищайте цикл ограничителем итераций и не используйте разыменование ссылок при массовой обработке.

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

Можно ли получить верхнего родителя одной встроенной функцией?

Нет, встроенного метода «верхний родитель» в платформе нет. Доступно только свойство Родитель для непосредственного родителя и оператор запроса В ИЕРАРХИИ для отбора потомков. Подъём к корню реализуется циклом, рекурсией или соединениями в запросе.

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

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

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

В цикле подъёма сохраняйте каждого родителя в массив или список значений до очередного перехода наверх. В запросе это делается серией самосоединений — каждая колонка будет соответствовать своему уровню.

Работает ли В ИЕРАРХИИ в динамических списках и СКД?

Да, оператор поддерживается в произвольных запросах динамических списков и в наборах данных СКД. Это стандартный способ фильтрации по ветке дерева в отчётах и подборах.

Что делать, если глубина иерархии неизвестна и соединений в запросе не хватает?

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

Влияет ли вид иерархии справочника на получение родителя?

На механику подъёма — нет: свойство Родитель работает одинаково. Различие в том, что при иерархии «групп и элементов» родителем может быть только группа, а при иерархии «элементов» — любой элемент. Учитывайте это при проверках ЭтоГруппа в логике обработки.