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