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