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