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