Как исправить ошибку «Поле объекта не обнаружено» при получении данных из результата запроса к табличной части в 1С?

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

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

Выясним причину возникновения ошибки

Рассмотрим, из-за чего возникает подобная ошибка при обращении к полям. Как правило, проблема кроется в сочетании двух основных факторов:

  1. Неправильный синтаксис запроса к табличной части (вложенные таблицы): Если в запросе к справочнику или документу использовать конструкцию вида Справочник.ТЧ.(Реквизит), платформа возвращает вложенную таблицу (значение с типом РезультатЗапроса). Это приводит к тому, что в выборке находится не само значение числа или строки, а целая таблица данных, к которой нельзя обратиться напрямую как к простому полю.
  2. Ошибочное обращение к объекту выборки: Значения колонок доступны в объекте ВыборкаИзРезультатаЗапроса после позиционирования методом Следующий(). Попытка обратиться напрямую к свойству объекта РезультатЗапроса (например, РезультатЗапроса.Цена) неизбежно вызовет ошибку, так как у самого объекта РезультатЗапроса нет динамических свойств с именами колонок — у него есть только методы Выбрать(), Выгрузить(), Пустой() и коллекция Колонки.

Посмотрим на ошибочный пример кода, который приводит к сбою:


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

Решение 1: Исправление запроса и правильный обход выборки

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

Рассмотрим правильный вариант реализации функции:


&НаСервере
Функция ИзвлечьЦену(Ссылка, Размер)
    Запрос = Новый Запрос;      
    Запрос.Текст = "ВЫБРАТЬ
    |    МонохромТЧМ.Цена КАК Цена
    |ИЗ
    |    Справочник.Монохром.ТЧМ КАК МонохромТЧМ
    |ГДЕ
    |    МонохромТЧМ.Ссылка = &Ссылка
    |    И МонохромТЧМ.Размер = &Размер";
    
    Запрос.УстановитьПараметр("Ссылка", Ссылка);
    Запрос.УстановитьПараметр("Размер", Размер);
    
    РезультатЗапроса = Запрос.Выполнить(); 
    
    Цена = 0;
    ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
    Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
        // Обращаемся к реквизиту через переменную текущей строки выборки
        Цена = ВыборкаДетальныеЗаписи.Цена;
    КонецЦикла;
    
    Возврат Цена;
КонецФункции

Решение 2: Оптимизация получения единичного значения

Проанализируем логику работы функции: если требуется получить всего одно значение (цену конкретного размера), избыточно перебирать строки в цикле Пока ... Цикл. Достаточно ограничить результат на уровне СУБД ключевым словом ПЕРВЫЕ 1 и прочитать строку через простое условие Если ... Тогда.

Также обратим внимание на директиву компиляции. Если функция вызывается из обработчика события формы (например, ПриИзменении) только для чтения данных и не изменяет реквизиты самой формы, рекомендуется использовать директиву &НаСервереБезКонтекста. Это исключает передачу контекста всей формы на сервер и обратно, существенно ускоряя работу интерфейса.

Посмотрим на оптимизированный вариант:


&НаКлиенте
Процедура МонохромРазмерПриИзменении(Элемент)
    ТекСтрока = Элементы.Монохром.ТекущиеДанные;
    Если ТекСтрока <> Неопределено Тогда
        ТекСтрока.Цена = ИзвлечьЦенуБезКонтекста(ТекСтрока.ВидПленки, ТекСтрока.Размер);
    КонецЕсли;
КонецПроцедуры

&НаСервереБезКонтекста
Функция ИзвлечьЦенуБезКонтекста(Ссылка, Размер)
    Запрос = Новый Запрос;      
    Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ 1
    |    МонохромТЧМ.Цена КАК Цена
    |ИЗ
    |    Справочник.Монохром.ТЧМ КАК МонохромТЧМ
    |ГДЕ
    |    МонохромТЧМ.Ссылка = &Ссылка
    |    И МонохромТЧМ.Размер = &Размер";
    
    Запрос.УстановитьПараметр("Ссылка", Ссылка);
    Запрос.УстановитьПараметр("Размер", Размер);
    
    РезультатЗапроса = Запрос.Выполнить(); 
    Выборка = РезультатЗапроса.Выбрать();
    
    Если Выборка.Следующий() Тогда
        Возврат Выборка.Цена;
    КонецЕсли;
    
    Возврат 0;
КонецФункции

Решение 3: Получение значения через выгрузку в таблицу значений

Рассмотрим еще один альтернативный способ чтения единичного значения без использования итератора ВыборкаИзРезультатаЗапроса — через метод Выгрузить(). Это удобно, когда требуется быстро проверить наличие строк и получить поле первой записи по индексу:


&НаСервереБезКонтекста
Функция ПолучитьЦенуЧерезТаблицу(Ссылка, Размер)
    Запрос = Новый Запрос;      
    Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ 1
    |    МонохромТЧМ.Цена КАК Цена
    |ИЗ
    |    Справочник.Монохром.ТЧМ КАК МонохромТЧМ
    |ГДЕ
    |    МонохромТЧМ.Ссылка = &Ссылка
    |    И МонохромТЧМ.Размер = &Размер";
    
    Запрос.УстановитьПараметр("Ссылка", Ссылка);
    Запрос.УстановитьПараметр("Размер", Размер);
    
    Таблица = Запрос.Выполнить().Выгрузить(); 
    
    Если Таблица.Количество() > 0 Тогда
        Возврат Таблица[0].Цена;
    КонецЕсли;
    
    Возврат 0;
КонецФункции

Сводные правила работы с результатами запросов

  1. Для выборки строк табличных частей всегда указывайте источник Справочник.Имя.ИмяТЧ или Документ.Имя.ИмяТЧ, избегая круглых скобок в секции ВЫБРАТЬ, если не требуется намеренно получить вложенную таблицу.
  2. Всегда считывайте данные из переменной выборки (Выборка.ИмяПоля) или выгруженной таблицы (Таблица[Индекс].ИмяПоля), а не из самого объекта РезультатЗапроса.
  3. Перед обращением к полям выборки обязательно позиционируйте указатель с помощью метода Следующий().
← На главную