Почему в отборе табличной части нет видов сравнения «В группе» и как настроить фильтр по иерархии

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

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

Выясним причину такого поведения платформы 1С:Предприятие и разберем практические способы реализации полноценного отбора по группам справочника.

Причины поведения платформы и архитектурные ограничения

Проанализируем, как работает механизм фильтрации строк табличного поля в обычном приложении:

  1. Локальная фильтрация в памяти: Для табличных частей и таблиц значений на форме отбор выполняется через свойство ОтборСтрок объекта ТабличноеПоле. Этот механизм работает исключительно с уже загруженной в оперативную память клиента коллекцией строк, не обращаясь к базе данных и не формируя запросов к СУБД.
  2. Отсутствие информации об иерархии: Ссылочные значения в памяти клиента представляют собой только ссылки (GUID). Чтобы определить, входит ли конкретный элемент в выбранную папку или группу справочника, требуется рекурсивный анализ иерархии родителей через обращение к таблицам базы данных. Так как стандартный ОтборСтрок не выполняет запросов к серверу при фильтрации, платформа принципиально исключает иерархические виды сравнения из диалога настройки.
  3. Разница с динамическими списками: В формах списков справочников и документов (СправочникСписок, ДокументСписок) данные изначально считываются порциями с помощью запросов к СУБД, поэтому там доступно полное дерево условий, включая ВИерархии.

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

Способ 1. Программное разворачивание группы в список значений

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

Посмотрим на пример реализации обработчика события при изменении поля отбора:


Процедура ПолеВводаГруппаНоменклатурыПриИзменении(Элемент)

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

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

    // Устанавливаем отбор по сформированному списку
    ЭлементыФормы.ТабличнаяЧасть.ОтборСтрок.Номенклатура.ВидСравнения = ВидСравнения.ВСписке;
    ЭлементыФормы.ТабличнаяЧасть.ОтборСтрок.Номенклатура.Значение = СписокДочерних;
    ЭлементыФормы.ТабличнаяЧасть.ОтборСтрок.Номенклатура.Использование = Истина;

КонецПроцедуры

Данный вариант работает быстро, прозрачно для пользователя и не требует переработки интерфейса самой таблицы.

Способ 2. Использование механизма отборов ПостроителяОтчета

Рассмотрим подход, который применяется в типовых обработках (например, в универсальной «Групповой обработке справочников и документов»). В таких обработках на форме размещается отбор, построенный на базе объекта ПостроительОтчета или ПостроительЗапроса.

Разберем по шагам создание такой структуры:

  1. В реквизитах формы создаем объект ПостроительОтчета.
  2. В качестве источника данных для построителя указываем нашу табличную часть или исходный запрос.
  3. Размещаем на форме табличное поле и связываем его путь к данным с ПостроительОтчета.Отбор.

Так как построитель отчетов умеет транслировать условия в запросы к базе данных при формировании выборки, в его диалоге выбора условий автоматически становятся доступны операторы В группе, В группе из списка и Не в группе.

Способ 3. Проверка через метод «ПринадлежитЭлементу» и служебную колонку

Если объем строк в табличной части невелик (до нескольких сотен строк) и не хочется выполнять запросы при каждом переключении фильтра, можно применить проверку принадлежности на клиенте:

  1. Добавим в табличную часть служебную невидимую булеву колонку, например ПодходитПоОтбору.
  2. При смене группы в цикле обойдем строки и проверим иерархию встроенным методом ссылки ПринадлежитЭлементу().
  3. Накладываем отбор на табличное поле по флагу.

Процедура ПрименитьФильтрПоИерархии(ВыбраннаяГруппа)

    Для Каждого Стр Из ТабличнаяЧасть Цикл
        Если Не ЗначениеЗаполнено(ВыбраннаяГруппа) Тогда
            Стр.ПодходитПоОтбору = Истина;
        Иначе
            // Проверяем вхождение элемента в группу
            Стр.ПодходитПоОтбору = Стр.Номенклатура.ПринадлежитЭлементу(ВыбраннаяГруппа);
        КонецЕсли;
    КонецЦикла;

    // Включаем фильтрацию по служебной колонке
    ЭлементыФормы.ТабличнаяЧасть.ОтборСтрок.ПодходитПоОтбору.Значение = Истина;
    ЭлементыФормы.ТабличнаяЧасть.ОтборСтрок.ПодходитПоОтбору.ВидСравнения = ВидСравнения.Равно;
    ЭлементыФормы.ТабличнаяЧасть.ОтборСтрок.ПодходитПоОтбору.Использование = ЗначениеЗаполнено(ВыбраннаяГруппа);

КонецПроцедуры

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

← На главную