Как исправить ошибку Метод объекта не обнаружен (Пустой) при работе с запросом в 1С

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

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

Выясняем причину ошибки: Результат запроса против Выборки

Проанализируем исходный код, который привел к ошибке. Основная проблема заключается в непонимании объектной модели встроенного языка 1С. Разберем цепочку действий при выполнении запроса:

  1. Объект Запрос выполняет текст SQL-запроса в базе данных.
  2. Метод Выполнить() возвращает объект типа РезультатЗапроса.
  3. Метод Выбрать(), вызванный от результата запроса, возвращает объект ВыборкаИзРезультатаЗапроса.

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


Выборка = МойЗапрос.Выполнить().Выбрать();
Если Не Выборка.Пустой() Тогда // ОШИБКА: у выборки нет метода Пустой()
    // ...
КонецЕсли;

Чтобы исправить ситуацию, нам необходимо разделить получение результата и получение выборки. Рассмотрим правильный алгоритм работы с объектами:


РезультатЗапроса = МойЗапрос.Выполнить(); // Получаем РезультатЗапроса
Если Не РезультатЗапроса.Пустой() Тогда   // Проверяем его на наличие данных
    Выборка = РезультатЗапроса.Выбрать(); // Создаем выборку для обхода
    Пока Выборка.Следующий() Цикл
        // Обработка данных
    КонецЦикла;
КонецЕсли;

Оптимизация обхода данных: Выгрузить() или Следующий()?

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

Метод Выгрузить() сразу преобразует весь результат запроса в объект ТаблицаЗначений. Это удобно, если вам нужно передать данные в другие функции или выполнить с ними сложные манипуляции в памяти. Однако помните, что при очень больших объемах данных (десятки и сотни тысяч строк) выгрузка в таблицу может потребовать значительного объема оперативной памяти.

Рассмотрим пример использования Выгрузить():


РезультатЗапроса = МойЗапрос.Выполнить();
ТаблицаРезультатов = РезультатЗапроса.Выгрузить();

Для Каждого СтрокаТЗ Из ТаблицаРезультатов Цикл
    // Работаем с данными таблицы
КонецЦикла;

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

Решаем проблему пустых данных на клиенте

Часто после исправления ошибки с методом Пустой() программисты замечают, что данные все равно не отображаются. Выясним причину этой ситуации. В управляемом приложении 1С 8.3 существует строгое разделение между Клиентом и Сервером.

Важный нюанс: Объект типа ТаблицаЗначений не может существовать на клиенте (в тонком или веб-клиенте). Если вы создали таблицу значений в серверной процедуре, она "умрет" сразу после завершения работы этой процедуры, если вы не передадите её данные в реквизит формы.

Разберем, как правильно передать данные на форму:

  1. Создайте на форме реквизит с типом СписокЗначений или Таблица (динамический список).
  2. Используйте метод ЗначениеВРеквизитФормы(), если работаете с коллекциями данных формы.
  3. Либо преобразуйте таблицу значений в Массив Структур, так как массив и структура являются мутабельными типами и могут передаваться между сервером и клиентом.

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


&НаСервере
Функция ПолучитьДанныеСервер(Год)
    Запрос = Новый Запрос;
    // ... установка параметров ...
    Результат = Запрос.Выполнить();
    
    // Возвращаем данные в виде массива структур для клиента
    Возврат Результат.Выгрузить().ВыгрузитьКолонку("Наименование_ПО"); 
КонецФункции

Повышаем производительность запроса (SARGability)

Проанализируем условие в запросе: ГДЕ Год(Срок_действия_лицензии) = &Год. С точки зрения производительности SQL-сервера, это "плохой" код. Когда мы используем функцию (например, Год()) над полем таблицы в условии ГДЕ, СУБД не может использовать индексы по этому полю. Ей приходится вычислить функцию для каждой строки в базе данных, что приводит к полному сканированию таблицы (Full Table Scan).

Рассмотрим, как оптимизировать этот участок кода, используя границы дат. Вместо одного параметра "Год", передадим начало и конец года:


Запрос.Текст = 
    "ВЫБРАТЬ 
    |	Наименование_ПО,
    |	Срок_действия_лицензии							
    |ИЗ 
    |	Справочник.Антивирусы КАК Антивирусы
    |ГДЕ 
    |	Срок_действия_лицензии МЕЖДУ &НачалоПериода И &КонецПериода";

Запрос.УстановитьПараметр("НачалоПериода", НачалоГода(ДатаИзФормы));
Запрос.УстановитьПараметр("КонецПериода", КонецГода(ДатаИзФормы));

Такой подход позволит системе мгновенно найти нужные записи, используя индекс по полю Срок_действия_лицензии.

Рекомендации по стандартам разработки 1С

Чтобы ваш код был профессиональным и понятным другим разработчикам, придерживайтесь следующих правил, выявленных в ходе анализа темы:

Соблюдение этих простых правил не только избавит вас от ошибки Метод объекта не обнаружен, но и сделает ваши информационные системы быстрыми и отказоустойчивыми.

← На главную