Как правильно реализовать фильтрацию в динамическом списке 1С через флажки на форме?

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

При разработке управляемых форм в 1С:Предприятие 8.3 часто возникает задача добавить на форму быстрые фильтры в виде флажков (переключателей типа Булево), которые управляют отображением строк в динамическом списке — например, показывать только проведенные документы, только помеченные на удаление или записи за определенный статус. Однако разработчики нередко сталкиваются с ситуацией: при включении флажка список фильтруется корректно, а при его снятии — вместо возврата к исходному полному списку — отображаются только непроведенные документы или список ведет себя непредсказуемо.

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

Анализ проблемы: почему параметры в запросе дают сбой при снятии флага

Рассмотрим типовой сценарий, с которого начинается данная ошибка. Разработчик создает произвольный запрос в динамическом списке и добавляет условие с расширением языка запросов СКД в фигурных скобках:


ВЫБРАТЬ
    ДокументПлан.Ссылка КАК Ссылка,
    ДокументПлан.Контрагент КАК Контрагент,
    ДокументПлан.Номер КАК Номер,
    ДокументПлан.Организация КАК Организация,
    ДокументПлан.Проведен КАК Проведен
ИЗ
    Документ.План КАК ДокументПлан
{ГДЕ
    ДокументПлан.Проведен = &Проведен}

На форму выносится реквизит ФлагПроведен (тип Булево), и в обработчике события ПриИзменении пишется следующий код:


&НаКлиенте
Процедура ФлагПроведенПриИзменении(Элемент)
    Список.Параметры.УстановитьЗначениеПараметра("Проведен", ФлагПроведен);
КонецПроцедуры

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

  1. При открытии формы: Параметр &Проведен еще не инициализирован. Блок в фигурных скобках {ГДЕ ...} платформой отбрасывается, и запрос выполняется без ограничений, возвращая все строки.
  2. При установке флажка (значение Истина): Вызывается метод УстановитьЗначениеПараметра. Параметр получает значение Истина. Платформа активирует блок ГДЕ, и результирующий SQL-запрос отбирает только проведенные документы.
  3. При снятии флажка (значение Ложь): Снова вызывается УстановитьЗначениеПараметра, но теперь туда передается значение Ложь. Платформа 1С не отключает условие, а выполняет запрос с жестким фильтром ДокументПлан.Проведен = Ложь. В итоге список начинает показывать только непроведенные документы вместо полного списка.

Почему исправление через «ВЫБОР» или «ИЛИ» в тексте запроса — это антипаттерн

Часто на форумах советуют обойти эту проблему непосредственно в запросе, написав конструкции вида:


ГДЕ
    (ДокументПлан.Проведен ИЛИ НЕ &Проведен)

или


ГДЕ
    ВЫБОР
        КОГДА &Проведен ТОГДА ДокументПлан.Проведен
        ИНАЧЕ ИСТИНА
    КОНЕЦ

Выясним, почему таких конструкций следует категорически избегать:

  1. Потеря индексов (Non-Sargable Query): СУБД (MS SQL Server, PostgreSQL) не может эффективно применить индекс по полю Проведен, когда в условии используются логические операторы ИЛИ или функция ВЫБОР над полями таблицы. Оптимизатор СУБД вынужден переключаться на полное сканирование таблицы (Index Scan / Table Scan).
  2. Просадка производительности динамического списка: Динамический список считывает данные порциями. Неоптимальный предикат заставляет СУБД перебирать миллионы строк в памяти при каждой прокрутке таблицы пользователем.

Способ 1. Управление отборами динамического списка (Рекомендуемый подход)

Наиболее правильное и производительное архитектурное решение в платформе 1С — вынести условие из текста запроса и управлять коллекцией Отбор динамического списка. В этом случае, если отбор выключен, условие физически не попадет в итоговый SQL-запрос, а при включении СУБД задействует штатный индекс.

Уберем блок {ГДЕ ...} из запроса динамического списка и реализуем установку отбора в модуле формы:


&НаКлиенте
Процедура ФлагПроведенПриИзменении(Элемент)
    УстановитьОтборПроведен(ФлагПроведен);
КонецПроцедуры

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

Способ 2. Использование функций Библиотеки Стандартных Подсистем (БСП)

Если разработка ведется в типовой конфигурации или конфигурации, использующей БСП, код можно сократить до одной строки с помощью встроенных сервисных методов общего модуля ОбщегоНазначенияКлиентСервер.

Посмотрим на пример обработчика:


&НаКлиенте
Процедура ФлагПроведенПриИзменении(Элемент)
    
    ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбораДинамическогоСписка(
        Список,
        "Проведен",
        Истина,
        ВидСравненияКомпоновкиДанных.Равно,
        ,
        ФлагПроведен
    );
    
КонецПроцедуры

Разберем параметры функции БСП:

  1. Список — имя реквизита формы с динамическим списком.
  2. "Проведен" — имя поля компоновки данных, по которому строится фильтр.
  3. Истина — значение, с которым сравнивается поле.
  4. ВидСравненияКомпоновкиДанных.Равно — вид сравнения.
  5. Шестой параметр (ФлагПроведен) — флаг Использование. Если переменная равна Ложь, процедура автоматически отключит элемент отбора.

Способ 3. Корректное управление доступностью параметров СКД

Если по условиям архитектуры вам строго необходимо оставить условие в тексте запроса через конструкцию {ГДЕ Поле = &Параметр}, необходимо управлять свойством Использование самого параметра в настройках компоновщика данных, а не просто перезаписывать его значение.

Разберем, как правильно отключить параметр в компоновщике настроек:


&НаКлиенте
Процедура ФлагПроведенПриИзменении(Элемент)
    УстановитьИспользованиеПараметраСписка("Проведен", Истина, ФлагПроведен);
КонецПроцедуры

&НаКлиенте
Процедура УстановитьИспользованиеПараметраСписка(ИмяПараметра, ЗначениеПараметра, Использовать)
    
    ИдентификаторПараметра = Новый ПараметрКомпоновкиДанных(ИмяПараметра);
    
    // Получаем элемент настройки параметра
    Элемент = Список.КомпоновщикНастроек.Настройки.ПараметрыДанных.Элементы.Найти(ИдентификаторПараметра);
    
    Если Элемент <> Неопределено Тогда
        Элемент.Значение      = ЗначениеПараметра;
        Элемент.Использование = Использовать;
    КонецЕсли;
    
КонецПроцедуры

Когда свойство Использование принимает значение Ложь, платформа 1С полностью убирает блок {ГДЕ ...} из формируемого SQL-запроса, и динамический список снова отображает все данные без наложения ограничений.

Сводная таблица подходов

  1. Отбор через свойства динамического списка (Способы 1 и 2): Максимальная производительность, автоматическая оптимизация запроса на уровне СУБД, чистота текста запроса без лишних условий. Рекомендуется как основной стандарт разработки.
  2. Управление свойством «Использование» параметров СКД (Способ 3): Применяется в сложных составных запросах, пакетах запросов и виртуальных таблицах, где параметры влияют на срез итоговых данных.
  3. Логические выражения в запросе (ВЫБОР / ИЛИ): Антипаттерн, приводящий к замедлению работы интерфейса и блокировкам данных при росте базы.
← На главную