Почему при вызове метода Выбрать() в 1С возникает ошибка чтения значения?

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

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

В чем причина ошибки чтения значения в отладчике

Главное отличие между методами заключается в способе представления данных в оперативной памяти:

  1. Метод Выгрузить() сразу считывает весь результат выполнения запроса из базы данных и формирует в памяти полноценную коллекцию — объект ТаблицаЗначений или ДеревоЗначений. Каждая строка и колонка этой таблицы уже физически созданы, поэтому отладчик без проблем считывает структуру и значения.
  2. Метод Выбрать() возвращает специализированный объект ВыборкаИзРезультатаЗапроса. Этот объект представляет собой однонаправленный курсор (итератор), предназначенный для последовательного порционного чтения данных, а не готовую загруженную таблицу.

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

Аналогичная ошибка возникает и в конце обработки: когда выборка прочитана целиком и очередной вызов метода Следующий() возвращает Ложь, указатель перемещается за пределы последней строки, и попытка прочитать колонки выборки снова вызовет ошибку.

Как правильно работать с выборкой из результата запроса

Для того чтобы получить доступ к полям выборки, необходимо сдвинуть указатель на первую или следующую строку с помощью метода Следующий(). Проанализируем стандартную структуру кода:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ПоступлениеТоваров.Ссылка КАК Док
    |ИЗ
    |	Документ.ПоступлениеТоваров КАК ПоступлениеТоваров
    |ГДЕ
    |	ПоступлениеТоваров.ДокЕГАИС <> ЗНАЧЕНИЕ(Документ.ТТНВходящаяЕГАИС.ПустаяСсылка)";

РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();

Пока Выборка.Следующий() Цикл
    // Внутри цикла курсор указывает на конкретную строку
    ТекущийДокумент = Выборка.Док;
КонецЦикла;

Если запрос должен вернуть гарантированно одну запись (например, при получении реквизита по ссылке или при использовании конструкции ВЫБРАТЬ ПЕРВЫЕ 1), обход в цикле не требуется, но позиционирование остается строго обязательным:


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

Ограничения объекта ВыборкаИзРезультатаЗапроса

При использовании потоковой выборки важно учитывать архитектурные особенности платформы 1С:

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

Как просмотреть все данные в отладчике без изменения исходного кода

Если в боевом коде написан потоковый обход через Выбрать(), но в процессе отладки требуется увидеть все строки результата целиком, не обязательно переписывать рабочий модуль. Достаточно использовать возможности окна «Вычислить выражение» (сочетание клавиш Shift + F9):

  1. Выделим переменную с объектом запроса или результата запроса.
  2. В окне вычисления выражения введем конструкцию: РезультатЗапроса.Выгрузить() или Запрос.Выполнить().Выгрузить().
  3. Нажмем кнопку просмотра значения (лупу). Платформа сформирует временную таблицу значений, которую можно изучить, отсортировать и отфильтровать прямо в интерфейсе отладчика. При этом исходная переменная Выборка останется нетронутой.
  4. Если требуется только узнать, вернул ли запрос какие-либо данные, используем быстрое свойство: РезультатЗапроса.Пустой(). Это булево значение, которое не сдвигает указатели и не тратит память на выгрузку строк.

Когда использовать Выбрать(), а когда Выгрузить()

Выбор между двумя методами определяет производительность и стабильность всей системы:

  1. Метод Выбрать() потребляет минимальный объем оперативной памяти сервера, так как данные считываются последовательными порциями. Этот вариант является стандартом для пакетной обработки данных, проведения документов, обменов и любых процедур, где размер выборки заранее неизвестен или может быть большим.
  2. Метод Выгрузить() загружает весь объем данных в память процесса единовременно. Его применение оправдано только тогда, когда над таблицей требуются операции поиска (Найти(), НайтиСтроки()), индексации, сортировки, либо результат передается напрямую в табличную часть или элемент интерфейса управляемой формы.
← На главную