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