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