Почему возникает ошибка «Недопустимое значение параметра» в методе ПостроительЗапроса.Отбор.Добавить и как её исправить?

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

При разработке алгоритмов обработки данных в 1С часто требуется отфильтровать строки в объекте ТаблицаЗначений по условиям сравнения: больше, меньше или не равно. Стандартный метод НайтиСтроки() для таких задач не подходит, поскольку принимает исключительно структуру и выполняет поиск строго по точному равенству. В таких ситуациях разработчики нередко прибегают к объекту ПостроительЗапроса, передавая таблицу через ОписаниеИсточникаДанных. Однако при попытке установить фильтр на строке кода тОтбор = Построитель.Отбор.Добавить("ИмяКолонки") система часто генерирует исключение: «Ошибка при вызове метода контекста (Добавить) по причине: Недопустимое значение параметра (параметр номер '1')». Разберем по шагам, почему возникает эта ошибка и какими способами ее можно устранить.

Анализ проблемы: механизм коллекции «ДоступныеПоля»

Выясним причину такого поведения платформы. Метод Построитель.Отбор.Добавить() в качестве первого параметра принимает имя поля только при соблюдении двух обязательных условий:

  1. Поле с данным именем зарегистрировано в системной коллекции Построитель.ДоступныеПоля.
  2. Для указанного поля флаг Отбор установлен в значение Истина.

Когда мы инициализируем объект ОписаниеИсточникаДанных на основе таблицы значений, платформа автоматически считывает метаданные колонок. Если колонка была добавлена простым указанием имени без описания типов (например, ТЗ.Колонки.Добавить("ВидОперации")), платформа считает тип поля неопределенным. В результате при формировании доступных полей свойству Отбор для этой колонки автоматически присваивается значение Ложь, либо поле вовсе блокируется для фильтрации. При попытке принудительно добавить такое поле в отбор платформа выбрасывает исключение недопустимого параметра.

Способ 1. Явная типизация колонок при создании таблицы (Рекомендуемый)

Посмотрим на пример правильного создания таблицы значений. Чтобы ПостроительЗапроса корректно распознал структуру данных и разрешил операции сравнения, колонкам необходимо явно назначать типы с помощью объекта ОписаниеТипов:


// Создаем таблицу с явным указанием типов колонок
ТЗ = Новый ТаблицаЗначений;

МассивТипов = Новый Массив;
МассивТипов.Добавить(Тип("Число"));
КвалификаторыЧисла = Новый КвалификаторыЧисла(10, 0, ДопустимыйЗнак.Любой);
ОписаниеТипаЧисло = Новый ОписаниеТипов(МассивТипов, , КвалификаторыЧисла);

ТЗ.Колонки.Добавить("ВидОперации", ОписаниеТипаЧисло);

// Заполняем таблицу данными
НоваяСтрока = ТЗ.Добавить();
НоваяСтрока.ВидОперации = 1;

// Настраиваем построитель запроса
Построитель = Новый ПостроительЗапроса;
Построитель.ИсточникДанных = Новый ОписаниеИсточникаДанных(ТЗ);

// Добавляем отбор без ошибок
тОтбор = Построитель.Отбор.Добавить("ВидОперации");
тОтбор.ВидСравнения = ВидСравнения.Больше;
тОтбор.Значение = 0;
тОтбор.Использование = Истина;

Построитель.Выполнить();
ТабРезультат = Построитель.Результат.Выгрузить();

Для простых базовых типов допустимо использовать сокращенную форму конструктора: ТЗ.Колонки.Добавить("ВидОперации", Новый ОписаниеТипов("Число"));. Как только у колонки появляется конкретный тип, платформа автоматически выставляет доступность отбора в истину.

Способ 2. Принудительное включение доступности отбора

Проанализируем ситуацию, когда таблица значений уже получена из внешнего источника или сложного алгоритма без явной типизации. Обратите внимание: свойство ТипЗначения у объекта КолонкаТаблицыЗначений доступно только для чтения, поэтому назначить тип существующей колонке «на лету» невозможно.

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


Построитель = Новый ПостроительЗапроса;
Построитель.ИсточникДанных = Новый ОписаниеИсточникаДанных(ТЗ);

// Принудительно разрешаем установку отбора по нетипизированной колонке
Если Построитель.ДоступныеПоля.Найти("ВидОперации") <> Неопределено Тогда
    Построитель.ДоступныеПоля.ВидОперации.Отбор = Истина;
КонецЕсли;

тОтбор = Построитель.Отбор.Добавить("ВидОперации");
тОтбор.ВидСравнения = ВидСравнения.Больше;
тОтбор.Значение = 0;
тОтбор.Использование = Истина;

Построитель.Выполнить();
ТабРезультат = Построитель.Результат.Выгрузить();

Способ 3. Фильтрация обходом в обратном цикле (Без построителя)

Рассмотрим альтернативное решение задачи. Если цель заключается исключительно в удалении неподходящих строк из исходной таблицы, использование тяжеловесных объектов (ПостроительЗапроса, временные таблицы или СКД) создает избыточную нагрузку на память. Быстрее и надежнее воспользоваться классическим удалением строк в обратном порядке:


// Удаляем строки, не удовлетворяющие условию (ВидОперации > 0)
Индекс = ТЗ.Количество() - 1;
Пока Индекс >= 0 Цикл
    Если ТЗ[Индекс].ВидОперации <= 0 Тогда
        ТЗ.Удалить(Индекс);
    КонецЕсли;
    Индекс = Индекс - 1;
КонецЦикла;

Преимущества данного подхода заключаются в том, что он совершенно нечувствителен к наличию или отсутствию объекта ОписаниеТипов у колонок, не требует инициализации вспомогательных объектов и выполняется максимально быстро на уровне оперативной памяти.

Важные ограничения и особенности платформы

При проектировании алгоритмов работы с коллекциями значений полезно помнить о следующих правилах платформы 1С:

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