Как проверить принадлежность элемента справочника к группе в 1С при любом уровне вложенности?

Программист 1С v8.3 (Обычные формы)
← На главную

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

Проблема использования свойства Родитель

Разберем типичную ситуацию. У нас есть иерархия: Группа А -> Группа 1 -> КарточкаНоменклатуры. Если мы попытаемся проверить принадлежность через свойство Родитель, то столкнемся с ограниченностью этого подхода. Свойство Родитель хранит ссылку только на непосредственного «отца» элемента. В нашем примере КарточкаНоменклатуры.Родитель вернет Группу 1.

Для проверки вхождения в Группу А нам пришлось бы писать конструкцию вида: Элемент.Родитель.Родитель. Проанализируем, почему это плохо:

  1. Неопределенная глубина: Мы никогда не знаем заранее, сколько уровней вложенности создаст пользователь. Если папок будет 10, код превратится в нечитаемую цепочку.
  2. Ошибки обращения: Если на каком-то этапе родитель окажется пустым (верхний уровень), обращение к следующему родителю вызовет ошибку выполнения.

Метод ПринадлежитЭлементу(): универсальное решение

Для эффективной проверки иерархии в платформе 1С предусмотрен встроенный метод ссылки — ПринадлежитЭлементу(). Этот метод проверяет, является ли переданная в параметре группа родителем для данного объекта на любом уровне иерархии.

Рассмотрим пример кода, который решает задачу автора темы:


// ГруппаА - это ссылка на группу, принадлежность к которой мы проверяем
// КарточкаНоменклатуры - ссылка на проверяемый элемент
Если КарточкаНоменклатуры.ПринадлежитЭлементу(ГруппаА) Тогда
    // Выполняем действия, если элемент входит в Группу А или любую её подгруппу
    Процедура1();
Иначе
    // Действия, если элемент не имеет отношения к Группе А
    Процедура2();
КонецЕсли;

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

Как избежать «магических» строк и поиска по наименованию

В ходе дискуссии на форуме было замечено, что использование НайтиПоНаименованию("Кровати") — это плохая практика («колхоз»). Если пользователь переименует группу в «Мебель для сна», ваш код перестанет работать. Выясним, как сделать ссылку на группу более надежной:

  1. Предопределенные элементы: Если логика программы жестко завязана на конкретную группу, сделайте её предопределенной в конфигураторе. Тогда обращение будет максимально простым: Справочники.Номенклатура.Кровати.
  2. Использование ГУИД: Можно найти группу по уникальному идентификатору, который не меняется при переименовании.
  3. Настройки/Константы: Позвольте пользователю самому выбрать целевую группу в настройках программы и сохраните ссылку в константу или параметр сеанса.

Проверка в запросах через оператор В ИЕРАРХИИ

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

Посмотрим на пример запроса, который выбирает всю номенклатуру, принадлежащую определенной группе:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Номенклатура.Ссылка КАК Ссылка
    |ИЗ
    |	Справочник.Номенклатура КАК Номенклатура
    |ГДЕ
    |	Номенклатура.Ссылка В ИЕРАРХИИ(&ЦелеваяГруппа)
    |	И НЕ Номенклатура.ЭтоГруппа";

Запрос.УстановитьПараметр("ЦелеваяГруппа", СсылкаНаГруппуА);
РезультатЗапроса = Запрос.Выполнить();

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

Безопасность кода: проверка на пустые ссылки

Проанализируем еще одну проблему, упомянутую на форуме: возникновение ошибок при пустых значениях. Перед вызовом методов иерархии всегда рекомендуется проверять ссылку на заполненность. Пустая ссылка не может «принадлежать» чему-либо в контексте бизнес-логики, а попытка вызвать метод от неопределенного объекта может привести к сбою.

Пример безопасной проверки в коде формы:


ГруппаДляПроверки = Справочники.Номенклатура.НайтиПоКоду("00123");

// Проверяем, что группа вообще найдена, прежде чем вызывать метод
Если НЕ ГруппаДляПроверки.Пустая() Тогда
    Если ТекущийОбъект.Родитель.ПринадлежитЭлементу(ГруппаДляПроверки) Тогда
        // Логика для вложенных элементов
        ЭлементыФормы.КнопкаСпецДействие.Доступность = Истина;
    КонецЕсли;
КонецЕсли;

Резюме

Подведем итог. Для проверки вложенности в 1С существует два основных инструмента:

Никогда не используйте конструкцию Родитель.Родитель..., так как она делает структуру кода хрупкой и зависимой от действий пользователя по перемещению папок в справочнике.

← На главную