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