Как правильно использовать ссылку из результата запроса и избежать ошибки Значение не является значением объектного типа

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

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

Разберем причину ошибки

Проанализируем фрагмент кода, который чаще всего приводит к проблеме:


Выб = Запрос.Выполнить().Выбрать().Следующий();
Если Выб = Ложь тогда
    // Обработка отсутствия данных
КонецЕсли;
Мат = Выб.Ссылка; // ОШИБКА ЗДЕСЬ

Выясним причину: метод Следующий() (или Next()) возвращает значение типа Булево (Истина, если следующая запись найдена, и Ложь, если записей больше нет). Когда вы пишете Выб = ...Следующий(), в переменную Выб попадает логическое значение, а не объект выборки. Следовательно, попытка обратиться к Выб.Ссылка воспринимается системой как попытка найти свойство Ссылка у логической переменной, что и вызывает ошибку.

Правильный алгоритм получения данных

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


// 1. Получаем результат выполнения запроса
РезультатЗапроса = Запрос.Выполнить();

// 2. Формируем выборку
Выборка = РезультатЗапроса.Выбрать();

// 3. Проверяем наличие данных и переходим к первой записи
Если Выборка.Следующий() Тогда
    // Теперь мы можем обращаться к полям запроса через объект Выборка
    МатериалСсылка = Выборка.Ссылка;
Иначе
    Сообщить("Данные не найдены");
КонецЕсли;

В этом случае переменная Выборка является объектом типа ВыборкаИзРезультатаЗапроса. Метод Следующий() позиционирует этот объект на нужную строку, после чего все поля, указанные в тексте запроса в секции ВЫБРАТЬ, становятся доступны как свойства этого объекта.

Оптимизация запроса для поиска одного элемента

Проанализируем ситуацию: если нам нужно найти только один конкретный элемент (например, по уникальному коду), хорошим тоном считается использование конструкции ВЫБРАТЬ ПЕРВЫЕ 1. Это оптимизирует работу СУБД. Посмотрим на обновленный пример кода:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ ПЕРВЫЕ 1
    |   Номенклатура.Ссылка КАК Ссылка
    |ИЗ
    |   Справочник.Номенклатура КАК Номенклатура
    |ГДЕ
    |   Номенклатура.Код = &Код";

Запрос.УстановитьПараметр("Код", "111");
Выборка = Запрос.Выполнить().Выбрать();

Если Выборка.Следующий() Тогда
    Мат = Выборка.Ссылка;
КонецЕсли;

Использование альтернативных методов поиска

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


КодПоиска = "111";
Мат = Справочники.Номенклатура.НайтиПоКоду(КодПоиска);

Если Мат.Пустая() Тогда
    Сообщить("Номенклатура с кодом " + КодПоиска + " не найдена!");
КонецЕсли;

Важный нюанс: метод НайтиПоКоду всегда возвращает ссылку. Если объект не найден, ссылка будет "пустой". Проверить это можно методом Пустая(). В отличие от запроса, этот метод всегда возвращает только одно значение, даже если в базе есть дубликаты кодов.

Типичные ошибки при именовании полей

Иногда разработчики используют сложные псевдонимы в запросе. Проанализируем пример:

Справочник.Номенклатура.Ссылка как ССЫЛКА_МАТЕРИАЛА

В этом случае при обходе выборки вы должны обращаться именно по этому псевдониму: Выборка.ССЫЛКА_МАТЕРИАЛА. Помните, что язык 1С нечувствителен к регистру, но чувствителен к правильности написания имен полей. Также стоит избегать использования зарезервированных слов в качестве псевдонимов, хотя платформа часто это позволяет.

Рекомендации по повышению производительности

Для того чтобы ваши запросы работали эффективно, придерживайтесь следующих правил:

  1. Индексация: Поиск по полю (например, КОДМАТ) будет быстрым только если это поле проиндексировано в конфигураторе. Проверьте свойство "Индексировать" у реквизита.
  2. Минимизация данных: Не выбирайте в запросе лишние поля. Если вам нужна только ссылка, не выбирайте наименование и все реквизиты.
  3. Избегайте ПолучитьОбъект(): Если вам нужно просто прочитать данные (наименование, артикул), добавьте их в запрос. Метод Ссылка.ПолучитьОбъект() — это крайне тяжелая операция, которая считывает все данные из базы, включая табличные части.
  4. Проверка на NULL: Если вы используете соединения таблиц (ЛЕВОЕ СОЕДИНЕНИЕ), всегда помните, что поля из правой таблицы могут содержать NULL, что требует обработки функцией ЕСТЬNULL() в тексте запроса.

Таким образом, ключ к решению проблемы заключается в четком понимании того, что возвращает каждый метод. Метод Выбрать() возвращает объект-итератор, а Следующий() лишь передвигает указатель и сообщает об успехе этого действия. Разделяя эти операции, вы пишете надежный и понятный код.

← На главную