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