Почему не задан параметр запроса и как правильно передавать динамические значения в 1С

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

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

Анализ проблемы и механизма работы свойств запроса

Проанализируем типичную ситуацию, с которой столкнулся разработчик. В коде выполнялась динамическая подстановка имени параметра в текст запроса:


// Формирование текста
Запрос.Текст = "... " + ?(ВсеХорошо, "&Парам", "&Парам2") + " КАК Реквизит ...";

// Попытка заполнения
Если ВсеХорошо Тогда
    Запрос.Параметры.Парам2 = Значение2;
КонецЕсли;

Запрос.ВыполнитьПакет();

В этом фрагменте допущены сразу две принципиальные ошибки:

  1. Логическое несоответствие условий: в тексте запроса при истинности переменной ВсеХорошо подставляется имя &Парам, а при значении Ложь — &Парам2. Однако в блоке условия значения присваивались наоборот: при значении Истина пытались заполнить Парам2, который в этот момент в тексте запроса отсутствовал.
  2. Особенность коллекции Запрос.Параметры: свойство Параметры объекта Запрос представляет собой обычную структуру. При создании запроса эта структура пуста. Платформа 1С не парсит текст запроса «на лету» при изменении свойства Текст и не создает ключи в структуре параметров автоматически. Прямое обращение через точку вида Запрос.Параметры.ИмяПараметра = Значение вызывает исключение «Поле объекта не обнаружено», так как такого ключа в структуре еще нет.

Синтаксический анализ текста на наличие параметров с символом & и проверка их заполненности выполняются только в момент вызова методов Выполнить() или ВыполнитьПакет(). Если параметр объявлен в тексте, но отсутствует в структуре параметров, платформа генерирует ошибку выполнения.

Способ 1. Использование метода Запрос.УстановитьПараметр (Базовое решение)

Выясним причину, почему прямой доступ через точку к структуре параметров считается некорректным. Для безопасной и штатной инициализации параметров предназначен специальный метод УстановитьПараметр(). Он проверяет наличие ключа в структуре параметров: если ключ существует, значение перезаписывается, а если отсутствует — создается новое свойство.

Если мы также хотим использовать прямое обращение к структуре, необходимо вызывать метод Запрос.Параметры.Вставить("ИмяПараметра", Значение), однако стандартным подходом платформы является именно УстановитьПараметр().

Посмотрим на пример корректного заполнения параметров:


Запрос.УстановитьПараметр("Парам", СсылкаНаДок);
Запрос.УстановитьПараметр("Парам2", СсылкаНаДок.Основание);

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

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

Разберем наиболее чистый и надежный подход к решению задачи. В большинстве случаев нет необходимости динамически менять сам текст запроса через конкатенацию строк (например, подставляя разные имена параметров &Парам и &Парам2). Если состав полей выборки одинаков, а меняется только источник (например, сам документ или его документ-основание), текст запроса оставляют статичным с одним типовым параметром.

Посмотрим, как выглядит реализация:


// Текст запроса остается типовым и неизменным
Запрос.Текст = 
    "ВЫБРАТЬ
    |   &пАРАМ КАК Реквизит
    |ИЗ
    |   Справочник.Номенклатура КАК Номенклатура";

// Условие отрабатывает на встроенном языке до передачи в запрос
ЗначениеПараметра = ?(ВсеХорошо, СсылкаНаДок, СсылкаНаДок.Основание);
Запрос.УстановитьПараметр("пАРАМ", ЗначениеПараметра);

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

Такой подход обеспечивает:

  1. Сохранение типового текста запроса без динамических склеек строк, что повышает читаемость кода.
  2. Возможность редактировать запрос с помощью визуального конструктора запросов без риска повредить синтаксис.
  3. Стабильность работы общего модуля для других документов и вызовов.

Способ 3. Перенос ветвления внутрь запроса через конструкцию ВЫБОР

Если логика требует передачи условий непосредственно в запрос без динамической модификации его текста, рассмотрим вариант с использованием конструкции ВЫБОР КОГДА ... ТОГДА ... ИНАЧЕ ... КОНЕЦ. В этом случае флаг условия и оба возможных значения передаются в виде параметров.

Посмотрим на пример реализации:


Запрос.Текст = 
    "ВЫБРАТЬ
    |   ВЫБОР 
    |       КОГДА &ВсеХорошо ТОГДА &Парам1
    |       ИНАЧЕ &Парам2
    |   КОНЕЦ КАК Реквизит";

Запрос.УстановитьПараметр("ВсеХорошо", ВсеХорошо);
Запрос.УстановитьПараметр("Парам1", СсылкаНаДок);
Запрос.УстановитьПараметр("Парам2", СсылкаНаДок.Основание);

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

Данный вариант сохраняет целостность текста запроса и позволяет СУБД самостоятельно определить итоговое значение поля на основе переданного булева флага.

← На главную