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