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