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