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

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

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

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

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

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

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

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

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

У каждого элемента иерархического справочника есть стандартный реквизит Родитель — ссылка на элемент или группу верхнего уровня. Если элемент находится в корне справочника, родитель пустой. У групп в иерархии групп и элементов признак ЭтоГруппа равен Истина.

Понимание типа иерархии важно, потому что от него зависит поведение методов и запросов. Например, проверка «элемент находится в группе» для иерархии элементов формулируется иначе: там проверяется подчинённость другому элементу, а не группе.

Метод ПринадлежитЭлементу — основной способ проверки

У объектов СправочникОбъект и СправочникСсылка есть метод ПринадлежитЭлементу(Родитель), который возвращает Истина, если текущий элемент находится в иерархии указанного родителя на любом уровне вложенности. Это самый простой и надёжный способ проверки в коде.

Если ЭлементСсылка.ПринадлежитЭлементу(ГруппаОборудование) Тогда

// Элемент находится в группе "Оборудование" или в любой её подгруппе

КонецЕсли;

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

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

Проверка через запрос: конструкция В ИЕРАРХИИ

В языке запросов 1С для проверки иерархии служит оператор В ИЕРАРХИИ. Он применяется к полю ссылки и параметру-родителю и выбирает все элементы, находящиеся в заданной ветке на любом уровне.

ВЫБРАТЬ

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

ИЗ

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

ГДЕ

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

И НЕ Номенклатура.ПометкаУдаления

В параметр можно передать одиночную ссылку или массив (список значений) ссылок — тогда отбор сработает по нескольким веткам сразу. Это удобно, когда пользователь выбрал несколько папок в отборе отчёта.

Проверка принадлежности одного элемента запросом

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

ВЫБРАТЬ ПЕРВЫЕ 1

ИСТИНА КАК ЕстьВИерархии

ИЗ

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

ГДЕ

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

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

Если выборка не пустая — элемент находится в иерархии. Такой подход удобен в серверных функциях проверки, куда уже передаются обе ссылки и не хочется читать объект целиком.

Порядок действий
  1. 1
    Определите тип иерархии справочника в конфигураторе (группы и элементы или элементы)
  2. 2
    Для разовой проверки в коде используйте Ссылка.ПринадлежитЭлементу(Группа)
  3. 3
    Для отбора списка или проверки в цикле напишите запрос с ГДЕ Ссылка В ИЕРАРХИИ(&Группа)
  4. 4
    Добавьте в запрос отсечение помеченных на удаление, если они не нужны
  5. 5
    Проверьте результат на тестовых данных с вложенностью два и более уровней

Почему сравнение родителя напрямую — ошибка

Начинающие разработчики часто пишут проверку вида Если Элемент.Родитель = Группа Тогда. Такое условие истинно только для элементов первого уровня вложенности. Если внутри группы есть подгруппы, все элементы подгрупп будут ошибочно отброшены.

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

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

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

Особенности для разных типов иерархии

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

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

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

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

ПринадлежитЭлементу()

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

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

Оптимален для отбора списков, проверок в циклах и отчётов. Требует написания запроса, но выполняется одним обращением к базе.

Сравнение Родитель = Группа

Допустимо только для отбора элементов первого уровня вложенности. Для проверки принадлежности ветке не подходит.

Рекурсивный обход родителей

Ручной подъём по цепочке Родитель в цикле. Оправдан только в редких случаях, когда нужны промежуточные уровни; иначе избыточен.

Проверка в динамических списках и отчётах СКД

В формах списков и отчётах на СКД проверку иерархии обычно делает пользователь через отбор. Чтобы отбор по группе работал с учётом вложенности, вид сравнения должен быть «В иерархии», а не «Равно». В настройках динамического списка это задаётся программно через элемент отбора:

ЭлементОтбора = Список.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));

ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Ссылка");

ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.ВИерархии;

ЭлементОтбора.ПравоеЗначение = ГруппаОтбора;

ЭлементОтбора.Использование = Истина;

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

При передаче списка групп в параметр отбора СКД убедитесь, что тип значения — список значений или массив ссылок нужного справочника. Передача строки с наименованием группы вместо ссылки приведёт к пустому результату без каких-либо сообщений об ошибке.

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

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

Элемент из подгруппы второго уровня
Норма

Попадает в выборку при отборе по верхней группе

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

Не попадает — используется сравнение родителя или вид сравнения Равно

Элемент из другой ветки
Норма

Не попадает в выборку

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

Попадает — проверьте, не перепутаны ли ссылки групп

Помеченные на удаление
Норма

Исключены отбором по ПометкаУдаления, если не нужны

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

Присутствуют в результате

Время выполнения отбора по большому списку
Норма

Доли секунды при запросе с В ИЕРАРХИИ

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

Секунды и минуты — вероятно, ПринадлежитЭлементу вызывается в цикле

Проверка корневых элементов и пустого родителя

Отдельная задача — определить, что элемент находится в корне справочника, то есть не входит ни в одну группу. Для этого проверяют родителя на пустоту: Если Элемент.Родитель.Пустая() Тогда. В запросе аналог — условие Родитель = &ПустаяСсылка с параметром пустой ссылки нужного типа или Родитель = ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка).

Обратная ситуация — найти элементы, у которых родитель «битый», то есть ссылка на несуществующий объект. Такое встречается после обменов и прямых манипуляций с данными. Признак — текст вида «Объект не найден» при попытке обратиться к родителю. Выявить такие элементы можно запросом с левым соединением к таблице справочника по полю Родитель и проверкой, что присоединённая ссылка равна NULL.

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

FAQ

Чем отличается «В иерархии» от «В списке» в отборе?

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

Можно ли проверить иерархию без обращения к базе, если ссылка уже есть?

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

Почему В ИЕРАРХИИ возвращает пустой результат, хотя группа заполнена?

Чаще всего в параметр передана ссылка на элемент, а не на группу (в справочнике с иерархией групп и элементов), либо передана ссылка другого типа — например, группа другого справочника. Проверьте тип и признак ЭтоГруппа у передаваемого значения.

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

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

Работает ли ПринадлежитЭлементу для планов видов характеристик?

Да, если у плана видов характеристик включена иерархия в настройках конфигурации. Метод и оператор В ИЕРАРХИИ работают одинаково для всех иерархических объектов: справочников, планов видов характеристик, планов видов расчёта.

Как получить полный путь элемента от корня до текущей группы?

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

Итог

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

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