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

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

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

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

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

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

Ниже разобраны рабочие способы проверки на встроенном языке 1С и в запросах, их ограничения, а также типичные ошибки, из-за которых проверка «вроде работает», но на реальных данных даёт неверный результат.

Как устроена иерархия справочников и почему это важно

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

Ключевой момент: Родитель хранит только ближайшую группу. Если товар «Молоко 3,2%» лежит в группе «Молочные продукты», которая вложена в «Продукты питания», то Родитель вернёт только «Молочные продукты». Проверка Элемент.Родитель = ГруппаПродукты даст Ложь, хотя логически товар в эту группу входит.

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

Способ 1. Сравнение с реквизитом Родитель

Самый простой вариант — прямое сравнение родителя элемента с нужной группой:

Если ЭлементСправочника.Родитель = ГруппаПроверки Тогда

// элемент лежит непосредственно в группе

КонецЕсли;

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

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

Способ 2. Запрос с оператором В ИЕРАРХИИ

Основной и рекомендуемый способ — запрос с оператором В ИЕРАРХИИ. Он учитывает все уровни вложенности и выполняется на стороне СУБД, что критично для больших справочников:

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

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

"ВЫБРАТЬ

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

|ИЗ

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

|ГДЕ

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

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

Запрос.УстановитьПараметр("Группа", ГруппаПроверки);

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

ВходитВГруппу = Не Запрос.Выполнить().Пустой();

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

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

bsl
// Быстрая проверка одного элемента
Функция ЭлементВходитВГруппу(Элемент, Группа)
    Запрос = Новый Запрос(
    "ВЫБРАТЬ ПЕРВЫЕ 1 Ссылка
    |ИЗ Справочник.Номенклатура
    |ГДЕ Ссылка = &Элемент И Ссылка В ИЕРАРХИИ(&Группа)");
    Запрос.УстановитьПараметр("Элемент", Элемент);
    Запрос.УстановитьПараметр("Группа", Группа);
    Возврат Не Запрос.Выполнить().Пустой();
КонецФункции

Способ 3. Обход иерархии в коде

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

Функция ВходитВГруппу(Элемент, Группа)

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

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

Если ТекущийРодитель = Группа Тогда

Возврат Истина;

КонецЕсли;

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

КонецЦикла;

Возврат Ложь;

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

Способ понятен и не требует построения запроса, но у него есть цена: каждое обращение к .Родитель по ссылке — это обращение к базе (в клиент-серверном варианте — к серверу). На глубокой иерархии и массовых проверках в цикле это заметно медленнее одного запроса.

Альтернатива — метод ВыборкаПоИерархии менеджера справочника: Справочники.Номенклатура.ВыбратьИерархически(ГруппаПроверки) вернёт выборку всех элементов группы с подгруппами. Он удобен, когда нужно перебрать содержимое группы, но для проверки одного элемента избыточен.

Сравнение способов проверки

Сравнение с Родителем

Быстро и просто, но видит только первый уровень. Подходит только для гарантированно плоской структуры.

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

Учитывает всю вложенность, быстро работает на СУБД, подходит для массовых выборок. Требует написания запроса.

Обход родителей в цикле

Гибко и наглядно, но порождает обращение к базе на каждый уровень. Не подходит для массовых проверок.

ВыбратьИерархически

Удобен для перебора содержимого группы, избыточен для проверки одного элемента.

Выбор способа под задачу

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

Отдельный случай — отбор в динамических списках и СКД. Там проверку вхождения в группу правильнее задавать через отбор с видом сравнения «В иерархии» по полю Ссылка, а не программной проверкой каждой строки. Это отдаёт работу СУБД и не ломает постраничную выборку списка.

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

Как выбрать способ

Группа не имеет и не будет иметь подгруппДостаточно сравнения Элемент.Родитель = Группа
Нужна проверка с учётом вложенных группИспользуйте запрос с оператором В ИЕРАРХИИ
Проверка выполняется в цикле по множеству элементовОдин запрос с В ИЕРАРХИИ для всех элементов, без обходов в коде
Нужно отобрать элементы в динамическом списке или СКДОтбор по полю Ссылка с видом сравнения «В иерархии»
Запрос недоступен, а глубина иерархии небольшаяЦикл по Элемент.Родитель до пустого значения

Типичные ошибки и подводные камни

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

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

Третья ошибка — игнорирование пометки удаления и предопределённости. Запрос с В ИЕРАРХИИ вернёт и помеченные на удаление элементы, если не добавить условие НЕ ПометкаУдаления. В отборах для бизнес-логики это часто критично.

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

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

Проверка результата и тестирование

После внедрения проверки её стоит протестировать на минимальном наборе случаев: элемент в самой группе, элемент во вложенной подгруппе второго-третьего уровня, элемент вне группы, элемент в соседней группе с похожим наименованием, пустая группа-параметр. Только прохождение всех пяти случаев подтверждает корректность.

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

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

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

Элемент непосредственно в группе
Норма

Проверка возвращает Истина

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

Возвращает Ложь — ошибка в параметрах запроса

Элемент во вложенной подгруппе 2–3 уровня
Норма

Возвращает Истина

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

Ложь — используется сравнение только с ближайшим Родителем

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

Возвращает Ложь

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

Истина — вероятно, сравнение по наименованию или пустая группа

Пустой параметр группы
Норма

Проверка отклоняется до запроса

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

Запрос выполняется с пустой ссылкой и даёт неожиданный результат

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

Исключён условием НЕ ПометкаУдаления

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

Попадает в выборку — условие забыто

Ограничения и особые случаи

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

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

На очень больших справочниках (сотни тысяч элементов, глубокая иерархия) производительность В ИЕРАРХИИ зависит от СУБД и индексов. Если запрос стал узким местом, рассмотрите кэширование результата проверки в соответствии или использование служебного регистра сведений с предвычисленной принадлежностью к группам верхнего уровня.

Итог

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

Для проверки вхождения элемента справочника в группу с учётом вложенных подгрупп используйте запрос с оператором В ИЕРАРХИИ. Сравнение с Родителем проверяет только первый уровень. Метода ПринадлежитЭлементу у справочников нет. Всегда проверяйте заполненность группы и исключайте помеченные на удаление элементы.

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

Есть ли в 1С готовый метод «ПринадлежитЭлементу» для справочников?

Нет. Метод ПринадлежитЭлементу существует у планов счетов и в отдельных механизмах планов видов характеристик, но не у справочников. Для справочников вхождение в группу проверяется запросом с оператором В ИЕРАРХИИ или обходом родителей в коде.

Почему сравнение Элемент.Родитель = Группа иногда не срабатывает?

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

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

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

Что вернёт В ИЕРАРХИИ, если группа не заполнена?

Поведение зависит от контекста, но пустая ссылка трактуется как корень иерархии, и результат может не совпасть с ожиданиями логики. Надёжное решение — перед выполнением запроса проверить ЗначениеЗаполнено(Группа) и при пустом значении сразу возвращать Ложь или обрабатывать случай отдельно.

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

Одним запросом: выберите из справочника ссылки, удовлетворяющие условию Ссылка В ИЕРАРХИИ(&Группа) И Ссылка В (&СписокЭлементов), передав список массивом в параметр. Это в разы быстрее, чем вызывать проверку для каждого элемента в цикле.

Работает ли В ИЕРАРХИИ, если у справочника иерархия элементов, а не групп?

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