В разработке на платформе 1С:Предприятие 8.2 и 8.3 в режиме обычного приложения часто возникает классическая задача: необходимо выполнить отбор в справочнике по определенному реквизиту. При этом критически важно сохранить иерархическую структуру (отображение «деревом»), но скрыть те группы, которые не содержат элементов, подходящих под условия фильтра. Разберем, почему стандартный механизм СправочникСписок не справляется с этой задачей «из коробки», и проанализируем эффективные методы обхода этого ограничения.
Проанализируем поведение платформы. Объект СправочникСписок в обычных формах оптимизирован для максимально быстрого вывода данных. Когда мы включаем режим иерархии, система строит дерево. Если накладывается отбор по реквизиту (например, «Проект» или «Ответственный»), платформа честно фильтрует элементы, но механизм отрисовки дерева требует показать всю цепочку родителей для каждого найденного элемента. Если родительская группа сама не соответствует условию отбора, она все равно остается видимой, чтобы не нарушать визуальную структуру иерархии. В итоге пользователь видит множество пустых папок, внутри которых «пусто», так как подчиненные элементы были отфильтрованы.
Выясним причину, по которой интерактивная настройка отбора не помогает. Дело в том, что свойство Использование у реквизита может быть установлено в значение «Для элементов», и тогда группы вообще игнорируются фильтром. Но даже если установлено «Для групп и элементов», алгоритм показа иерархии в обычном приложении всегда имеет приоритет над фильтрацией пустых узлов. Рассмотрим пошагово, как решить эту проблему программными методами.
Это наиболее надежный и часто используемый способ. Суть его заключается в том, чтобы самостоятельно подготовить список всех элементов и групп, которые должны попасть в видимость, и передать этот список в отбор по полю Ссылка.
Разберем алгоритм реализации:
СписокЗначений.СправочникСписок.Отбор.Ссылка с видом сравнения ВидСравнения.ВСписке.Посмотрим на пример кода, который реализует эту логику:
// Предположим, нам нужно отобрать номенклатуру по реквизиту "Менеджер"
Процедура УстановитьИерархическийОтбор()
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗЛИЧНЫЕ
| Номенклатура.Ссылка КАК Ссылка
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Менеджер = &Менеджер
|
|УПОРЯДОЧИТЬ ПО
| Номенклатура.Ссылка ИЕРАРХИЯ";
Запрос.УстановитьПараметр("Менеджер", ВыбранныйМенеджер);
РезультатЗапроса = Запрос.Выполнить();
СписокСсылок = Новый СписокЗначений;
СписокСсылок.ЗагрузитьЗначения(РезультатЗапроса.Выгрузить().ВыгрузитьКолонку("Ссылка"));
// Применяем отбор к СправочникСписок
ОтборСсылка = СправочникСписок.Отбор.Ссылка;
ОтборСсылка.ВидСравнения = ВидСравнения.ВСписке;
ОтборСсылка.Значение = СписокСсылок;
ОтборСсылка.Использование = Истина;
КонецПроцедуры
Важный момент: использование конструкции УПОРЯДОЧИТЬ ПО ... ИЕРАРХИЯ в запросе позволяет автоматически включить в результат все вышестоящие группы. Если мы передадим в список только конечные элементы, то при включенной иерархии в списке они могут просто исчезнуть, так как платформа не найдет их «родителей» в разрешенном списке ссылок.
Если справочник очень большой, и формирование списка ссылок через запрос начинает занимать много времени, проанализируем альтернативу — использование ПостроительОтчета. Этот объект в обычных формах позволяет выводить данные в табличное поле, имитируя поведение динамического списка.
Рассмотрим преимущества этого метода:
СправочникСписок.Однако у этого метода есть существенный минус: вы теряете стандартные возможности «живого» списка справочника (быстрое добавление, перетаскивание элементов Drag-and-drop, интерактивное изменение иерархии пользователем). Этот метод хорош для форм выбора или специализированных АРМ, но редко подходит для основной формы списка справочника.
Если задача отбора стоит не в плоскости удобства интерфейса, а в плоскости безопасности (например, менеджер должен видеть только свои группы и товары), рассмотрим механизм RLS (Row Level Security). Это единственный способ, при котором данные фильтруются на уровне СУБД еще до попадания в приложение.
Проанализируем ситуацию: когда настроен RLS, система автоматически скрывает записи, на которые у пользователя нет прав. Если права отсутствуют и на группу, и на все её содержимое, папка исчезнет из списка сама собой. Внимание: это самый ресурсозатратный метод. Неправильно написанный запрос в шаблоне RLS может привести к катастрофическому падению производительности при открытии списка номенклатуры или контрагентов, так как сервер будет проверять условия доступа для каждой строки и всей цепочки её родителей.
Независимо от выбранного способа, мы должны обеспечить скорость работы. Если вы выполняете отбор по какому-либо реквизиту, убедитесь, что для этого реквизита в конфигураторе установлено свойство Индексировать. Без индекса любой программный отбор в обычном приложении на справочнике объемом более 10-20 тысяч записей будет вызывать заметные задержки (фризы) интерфейса при каждом обновлении.
Мы выяснили, что штатного переключателя «Скрывать пустые группы» в СправочникСписок обычного приложения не существует. Для решения задачи мы рекомендуем использовать программную установку отбора по полю Ссылка с предварительным получением списка разрешенных объектов через запрос с иерархией. Это решение является сбалансированным по сложности реализации и предсказуемости результата.