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