Почему возникает ошибка «Значение не является значением объектного типа (УстановитьПараметр)» в 1С и как ее исправить?

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

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

Причина 1: Перезапись переменной запроса строковым значением

Проанализируем фрагмент кода, в котором возникает исключение:


Запрос = Новый Запрос;
Запрос = "ВЫБРАТЬ
         |    ОтправкаМашиныМаршрут.Заявка.Ссылка,
         |    ОтправкаМашиныМаршрут.Заявка.Организация КАК Организация
         |ИЗ
         |    Документ.ОтправкаМашины.Маршрут КАК ОтправкаМашиныМаршрут
         |ГДЕ
         |    ОтправкаМашиныМаршрут.Ссылка = &ОтправкаСсылка";
Запрос.УстановитьПараметр("ОтправкаСсылка", Отправка);

Посмотрим, что здесь происходит: сначала создается экземпляр объекта Запрос с помощью конструктора Новый Запрос. Однако на следующем шаге вместо присвоения текста свойству Текст происходит полная перезапись переменной Запрос строковым литералом (Запрос = "ВЫБРАТЬ...").

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

Для устранения этой ошибки текст запроса необходимо присваивать специализированному свойству Текст:


Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
               |    ОтправкаМашиныМаршрут.Заявка КАК Заявка,
               |    ОтправкаМашиныМаршрут.Заявка.Организация КАК Организация
               |ИЗ
               |    Документ.ОтправкаМашины.Маршрут КАК ОтправкаМашиныМаршрут
               |ГДЕ
               |    ОтправкаМашиныМаршрут.Ссылка = &ОтправкаСсылка";

Также хорошей практикой является передача текста запроса непосредственно в конструктор при инициализации объекта. Это исключает случайную перезапись переменной:


ТекстЗапроса = "ВЫБРАТЬ
               |    ОтправкаМашиныМаршрут.Заявка КАК Заявка,
               |    ОтправкаМашиныМаршрут.Заявка.Организация КАК Организация
               |ИЗ
               |    Документ.ОтправкаМашины.Маршрут КАК ОтправкаМашиныМаршрут
               |ГДЕ
               |    ОтправкаМашиныМаршрут.Ссылка = &ОтправкаСсылка";

Запрос = Новый Запрос(ТекстЗапроса);

Причина 2: Передача объекта вместо ссылки в параметры запроса

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

Запросы в 1С работают на уровне базы данных СУБД с ссылочными типами данных (ДокументСсылка, СправочникСсылка и т. д.). Передача объекта документа (ДокументОбъект) в качестве условия для ссылочного поля Ссылка приведет к ошибке несовместимости типов или к пустой выборке.

Разберем, почему вызов ПолучитьОбъект() здесь избыточен:

  1. Метод ПолучитьОбъект() полностью считывает данные документа и всех его табличных частей из базы в оперативную память сервера. Если цель — просто выполнить запрос, получение объекта создает лишнюю и неэффективную нагрузку на систему.
  2. Если исходная ссылка уже доступна в переменной СсылкаНаОбъект, ее следует напрямую передать в метод УстановитьПараметр.

// Передаем исходную ссылку без избыточного чтения объекта в память
Запрос.УстановитьПараметр("ОтправкаСсылка", СсылкаНаОбъект);

Если объект документа уже был ранее получен в коде для редактирования данных, в запрос передается ссылка через обращение к свойству Ссылка:

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

Оптимизация текста запроса

Обратим внимание на поля выборки в исходном тексте запроса:

  1. Конструкция ОтправкаМашиныМаршрут.Заявка.Ссылка содержит избыточное разыменование. Реквизит Заявка уже содержит ссылку на документ. Лишнее обращение через точку заставляет платформу строить неявное соединение (LEFT JOIN) с таблицей заявок. Достаточно написать ОтправкаМашиныМаршрут.Заявка КАК Заявка.
  2. Обращение ОтправкаМашиныМаршрут.Заявка.Организация также выполняет неявное соединение. Для небольших выборок это допустимо, однако при обработке больших массивов данных рекомендуется использовать явное левое соединение с таблицей документа заявки.

Итоговый корректный вариант кода

Объединим все исправления в единый рабочий пример:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |    ОтправкаМашиныМаршрут.Заявка КАК Заявка,
    |    ОтправкаМашиныМаршрут.Заявка.Организация КАК Организация
    |ИЗ
    |    Документ.ОтправкаМашины.Маршрут КАК ОтправкаМашиныМаршрут
    |ГДЕ
    |    ОтправкаМашиныМаршрут.Ссылка = &ОтправкаСсылка";

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

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

Пока Выборка.Следующий() Цикл
    // Обработка полученных данных
КонецЦикла;

Следуя этим правилам, мы избегаем перезаписи системных объектов простыми типами данных и обеспечиваем оптимальное взаимодействие с базой данных без лишней нагрузки на сервер.

← На главную