Почему в отладчике 1С возникает ошибка чтения значения при обращении к результату запроса?

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

При разработке запросов и функций получения данных из регистров сведений разработчики нередко сталкиваются с ситуацией, когда код падает с ошибкой, а в окне вычисления выражений отладчика отображается «Ошибка чтения значения». Разберем подробно, почему возникает такое поведение платформы, как правильно позиционировать курсор выборки и как грамотно оптимизировать код получения среза данных.

Причины возникновения ошибки в отладчике

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

  1. Непустая выборка не гарантирована: Если запрос не нашел ни одной подходящей записи в базе данных, метод Выборка.Следующий() возвращает Ложь. Курсор выборки остается в невалидном состоянии. Попытка прочитать свойство (например, Выборка.СтавкаРуб) в отладчике вызовет «Ошибка чтения значения», а в режиме предприятия — исключение «Поле объекта не обнаружено».
  2. Передача некорректных параметров: Если в фильтр запроса передается ссылка не того типа (например, передали Контрагента вместо Партнера) или значение Неопределено, запрос возвращает пустую таблицу.
  3. Синтаксические неточности: Пропуск круглых скобок при вызове методов (например, Запрос.Выполнить.Выбрать вместо Запрос.Выполнить().Выбрать()) приводит к попытке обращения к методам как к свойствам, что нарушает цепочку вызовов.
  4. Неявные соединения в тексте запроса: Конструкция вида ЧасоваяСтавкаПоКлиенту.Партнер.Ссылка выполняет лишнее разыменование ссылочного типа, заставляя СУБД создавать неявное соединение (LEFT JOIN). Так как поле Партнер само по себе содержит ссылку, обращаться к его реквизиту Ссылка избыточно.

Решение 1. Безопасное получение данных через срез последних с проверкой выборки

Рассмотрим правильное построение функции. Если регистр сведений является периодическим, обращаться напрямую к физической таблице некорректно — это вернет все исторические записи без гарантии актуальности. Необходимо использовать виртуальную таблицу СрезПоследних, передавая параметры отбора непосредственно в параметры таблицы.

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


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

Обратите внимание на конструкцию Если Выборка.Следующий() Тогда. Она предотвращает обращение к полям пустой выборки и полностью устраняет ошибку чтения значения.

Решение 2. Использование объектной модели менеджера регистра

Если требуется получить актуальные значения ресурсов периодического регистра по конкретным измерениям без написания сложного текста запроса, воспользуемся штатным методом менеджера регистра сведений ПолучитьПоследнее().

Посмотрим на пример реализации:


Функция ПолучитьСтавкуЧерезМенеджер(Партнер, Период = Неопределено) Экспорт
    
    ДатаСреза = ?(ЗначениеЗаполнено(Период), Период, ТекущаяДатаСеанса());
    
    Отбор = Новый Структура;
    Отбор.Вставить("Партнер", Партнер);
    
    // Метод возвращает структуру со значениями ресурсов на указанную дату
    ЗначенияРесурсов = РегистрыСведений.ЧасоваяСтавкаПоКлиенту.ПолучитьПоследнее(ДатаСреза, Отбор);
    
    Возврат ЗначенияРесурсов.СтавкаРуб;
    
КонецФункции

Преимущество метода ПолучитьПоследнее() заключается в том, что даже при полном отсутствии записей в регистре он возвращает структуру с инициализированными значениями по умолчанию (для числовых колонок это число 0), исключая аварийные остановки программы.

Рекомендации по чистоте и надежности кода

Выделим основные правила, которые помогут избежать подобных ошибок в будущем:

  1. Передавайте контекст явно: Не обращайтесь к реквизитам форм или внешним переменным напрямую из общих функций. Всегда передавайте нужные ссылки через формальные параметры функции (например, передавайте Партнер, а не полагайтесь на глобальные реквизиты).
  2. Не используйте разыменование без необходимости: Сравнивайте ссылки напрямую: ГДЕ Партнер = &Партнер вместо ГДЕ Партнер.Ссылка = &Партнер.
  3. Контролируйте экспортность методов: Ключевое слово Экспорт необходимо указывать только тем процедурам и функциям, которые предназначены для вызова из других модулей конфигурации. Внутренние вспомогательные функции модуля должны оставаться локальными.
← На главную