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