Как исправить ошибки обращения к полям и преобразования к типу Число в результатах запроса 1С?

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

При разработке и доработке алгоритмов на платформе 1С:Предприятие начинающие специалисты часто сталкиваются с ошибками времени выполнения при обработке результатов запросов. Типичными проблемами являются исключения вида «Поле объекта не обнаружено» и «Преобразование значения к типу Число не может быть выполнено». Разберем по шагам, почему возникают эти ошибки на конкретном практическом примере, и выясним, как правильно выстраивать логику запроса и постобработки данных.

Анализ исходного кода и причин возникновения ошибок

Рассмотрим исходную процедуру, в которой выполняется запрос к справочнику и последующая попытка обработки полученных данных:


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

Запрос.УстановитьПараметр("КодМенеджера", КодМенеджера);

МенеджерЗапрос = Запрос.Выполнить().Выгрузить();

Если МенеджерЗапрос.Количество() > 0 Тогда
    Возврат Формат(Число(МенеджерЗапрос[0].ИДМенеджер),"ЧГ=0");
Иначе
    Возврат Формат(Число(?(обПустоеЗначение(КодМенеджера),0,КодМенеджера)),"ЧГ=0");
КонецЕсли;

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

  1. Ошибка видимости полей результата запроса: при попытке обратиться к МенеджерЗапрос[0].КодМенеджера платформа выдает ошибку «Поле объекта не обнаружено». Это происходит потому, что поле КодМенеджера объявлено только во вложенной таблице МО. В верхнем блоке ВЫБРАТЬ указано единственное поле: МО.Менеджер КАК ИДМенеджер. Результирующая ТаблицаЗначений содержит только одну колонку — ИДМенеджер.
  2. Попытка привести объектную ссылку к числу: в колонке ИДМенеджер возвращается поле Ссылка типа СправочникСсылка (например, конкретный менеджер). Функция платформы Число() умеет преобразовывать строки (например, "000017") и булевы значения, но не может преобразовать ссылку на объект базы данных. Попытка выполнить Число(МенеджерЗапрос[0].ИДМенеджер) неизбежно приводит к аварийному завершению с ошибкой «Преобразование значения к типу Число не может быть выполнено».

Шаг 1. Исправление логики получения полей в запросе

Выясним причину: если нам требуется получить числовое представление кода менеджера или саму ссылку, все эти поля необходимо явно запросить на верхнем уровне выборки. Разыменование полей через точку в коде 1С (например, МенеджерЗапрос[0].ИДМенеджер.Код) порождает неявные дополнительные запросы к СУБД, что ухудшает производительность.

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


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

Запрос.УстановитьПараметр("КодМенеджера", КодМенеджера);

Обратим внимание на ключевые оптимизации:

  1. Вместо конструкции ОБЪЕДИНИТЬ ВСЕ с вложенными таблицами используется простое условие с логическим оператором ИЛИ. Это существенно упрощает план выполнения запроса в СУБД.
  2. Использована конструкция ВЫБРАТЬ ПЕРВЫЕ 1, так как для поиска конкретного значения достаточно первой найденной записи.

Шаг 2. Корректная обработка результата запроса без выгрузки в память

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

Посмотрим на пример оптимального алгоритма постобработки:


Выборка = Запрос.Выполнить().Выбрать();

Если Выборка.Следующий() Тогда
    // Преобразуем строковый код менеджера в число без лидирующих нулей
    Попытка
        Возврат Формат(Число(Выборка.Код), "ЧГ=0");
    Исключение
        Возврат 0;
    КонецПопытки;
Иначе
    Попытка
        Возврат Формат(Число(?(обПустоеЗначение(КодМенеджера), 0, КодМенеджера)), "ЧГ=0");
    Исключение
        Возврат 0;
    КонецПопытки;
КонецЕсли;

Особенности работы с функцией Число() и строковыми кодами

Разберем важные нюансы преобразования типов в платформе 1С:

  1. Лидирующие нули: встроенная функция Число("000017") корректно отсекает нули в начале строки и возвращает число 17. Создавать вспомогательные циклы по удалению нулей через Лев() или Прав() не требуется.
  2. Нечисловые символы: если код справочника содержит префиксы (например, "УТ-000017") или пробелы, функция Число() вызовет исключение. В таких случаях вызов функции обязательно оборачивается в блок Попытка ... Исключение.
  3. Проверка на пустоту: для быстрой проверки наличия записей в запросе без извлечения данных рекомендуется использовать метод Запрос.Выполнить().Пустой().
← На главную