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