Как избежать ошибки «Поле объекта не обнаружено» при проверке условий в 1С?

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

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

Почему возникает ошибка при проверке условия?

Проанализируем пример кода, вызывающий исключение:


Если Выборка.ВидОперации = Перечисления.ВидыОперацийПоЗарплате.ДоговорАвторскогоЗаказа
    Или Выборка.ВидОперации = Перечисления.ВидыОперацийПоЗарплате.ДоговорРаботыУслуги
    Или Выборка.ВидРасчета.СпособОтраженияЗарплатыВБухучете.Наименование = "70606810400004810101" Тогда
    // Действия при выполнении условия
КонецЕсли;

В этом фрагменте скрыты сразу две архитектурные проблемы платформы:

  1. Отсутствие ленивых (сокращенных) вычислений в 1С. В логических выражениях операторы И и ИЛИ вычисляются полностью. Даже если первое условие истинно, платформа все равно продолжит вычислять выражения справа. Если в объекте Выборка отсутствует колонка ВидРасчета, обращение к ней немедленно вызовет фатальную ошибку, независимо от значения первого операнда.
  2. Множественное разыменование через точку. Конструкция вида Выборка.ВидРасчета.СпособОтраженияЗарплатыВБухучете.Наименование порождает скрытые неявные обращения к базе данных. Кроме того, если хотя бы одно промежуточное значение окажется равным Неопределено или NULL, выполнение также завершится ошибкой.

Способ 1. Унификация структуры данных в запросе (рекомендуемый)

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


// В первой процедуре (где есть вид расчета):
Запрос1 = Новый Запрос;
Запрос1.Текст = 
    "ВЫБРАТЬ
    |	Таблица.ВидОперации КАК ВидОперации,
    |	Таблица.ВидРасчета КАК ВидРасчета,
    |	Таблица.ВидРасчета.СпособОтраженияЗарплатыВБухучете.Наименование КАК НаименованиеСпособа
    |ИЗ
    |	Документ.НачислениеЗарплаты.Начисления КАК Таблица";

// Во второй процедуре (где вид расчета отсутствует):
Запрос2 = Новый Запрос;
Запрос2.Текст = 
    "ВЫБРАТЬ
    |	Таблица.ВидОперации КАК ВидОперации,
    |	ЗНАЧЕНИЕ(ПланВидовРасчета.Начисления.ПустаяСсылка) КАК ВидРасчета,
    |	"""" КАК НаименованиеСпособа
    |ИЗ
    |	Документ.ВыплатаПоДоговорам.Договоры КАК Таблица";

Теперь в алгоритме обработки мы можем безопасно и компактно проверить значение реквизита:


Если Выборка.ВидОперации = Перечисления.ВидыОперацийПоЗарплате.ДоговорАвторскогоЗаказа
    Или Выборка.ВидОперации = Перечисления.ВидыОперацийПоЗарплате.ДоговорРаботыУслуги
    Или Выборка.НаименованиеСпособа = "70606810400004810101" Тогда
    // Корректное выполнение без риска ошибки
КонецЕсли;

Способ 2. Разделение составного условия на вложенные блоки

Если изменить исходный запрос невозможно, разберем способ обхода ошибки с помощью последовательных проверок. Разделим условие на вложенные операторы Если, чтобы обращение к потенциально отсутствующему полю происходило только в изолированной ветке.


УсловиеВыполнено = Ложь;

Если Выборка.ВидОперации = Перечисления.ВидыОперацийПоЗарплате.ДоговорАвторскогоЗаказа
    Или Выборка.ВидОперации = Перечисления.ВидыОперацийПоЗарплате.ДоговорРаботыУслуги Тогда
    УсловиеВыполнено = Истина;
Иначе
    // Проверяем наличие поля перед его чтением
    Попытка
        Если ЗначениеЗаполнено(Выборка.ВидРасчета) 
            И ЗначениеЗаполнено(Выборка.ВидРасчета.СпособОтраженияЗарплатыВБухучете) Тогда
            Если Выборка.ВидРасчета.СпособОтраженияЗарплатыВБухучете.Наименование = "70606810400004810101" Тогда
                УсловиеВыполнено = Истина;
            КонецЕсли;
        КонецЕсли;
    Исключение
        // Поле отсутствует в выборке, пропускаем проверку
        УсловиеВыполнено = Ложь;
    КонецПопытки;
КонецЕсли;

Если УсловиеВыполнено Тогда
    // Выполняем целевое действие
КонецЕсли;

Способ 3. Проверка наличия колонки в результате запроса

Выясним, как заранее определить состав колонок до начала итераций, чтобы не использовать конструкцию Попытка ... Исключение внутри тела цикла.

Перед началом обхода выборки проверим наличие нужного поля в коллекции колонок объекта РезультатЗапроса:


Результат = Запрос.Выполнить();
ЕстьВидРасчета = (Результат.Колонки.Найти("ВидРасчета") <> Неопределено);

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

Способ 4. Безопасное чтение данных через структуры

Если для передачи параметров используется объект Структура, то наличие нужного свойства проверяется встроенным методом Свойство():


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

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

← На главную