К статье
Практический материал

Разработка и Конфигурация · 12 мин

Как в 1С проверить, существует ли поле

Как в 1С проверить, существует ли поле: проверка реквизита через метаданные, свойства структуры, поля запроса. Примеры кода, ошибки и частые вопросы.

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

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

Ниже разобраны рабочие приёмы с примерами кода, их ограничения и типичные ошибки, которые приводят к ложным результатам проверки.

Почему нельзя просто обратиться к полю и поймать ошибку

Начинающие разработчики часто пишут обращение вида Если Документ.Комментарий2 <> "" Тогда, не проверяя, есть ли такой реквизит у конкретного вида документа. Если реквизита нет в метаданных, платформа прерывает выполнение с ошибкой «Поле объекта не обнаружено (Комментарий2)». Это не исключение, которое можно проигнорировать, — обработка останавливается, а пользователь видит техническое сообщение.

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

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

Проверка реквизита объекта через метаданные

Основной способ для справочников, документов, планов счетов и других объектов метаданных — поиск реквизита в коллекции Метаданные().Реквизиты. Метод Найти() возвращает объект описания реквизита или Неопределено, если реквизита нет.

Функция ЕстьРеквизит(Объект, ИмяРеквизита)

МетаданныеОбъекта = Объект.Метаданные();

Возврат МетаданныеОбъекта.Реквизиты.Найти(ИмяРеквизита) <> Неопределено;

КонецФункции

// Использование

Если ЕстьРеквизит(ДокументОбъект, "Согласовано") Тогда

ДокументОбъект.Согласовано = Истина;

КонецЕсли;

Такой подход работает и для табличных частей: у табличной части есть своя коллекция реквизитов, доступная через метаданные. Например, МетаданныеОбъекта.ТабличныеЧасти.Найти("Товары").Реквизиты.Найти("Скидка"). Сначала проверяют существование самой табличной части, затем — реквизита внутри неё.

Важно понимать, что метод Метаданные() доступен у объектов данных (ссылок и объектов), но не у произвольных значений. Для структур, соответствий и строк таблиц значений этот способ неприменим — там используются другие механизмы.

Порядок проверки реквизита документа
  1. 1
    Получите объект или ссылку на документ в коде
  2. 2
    Вызовите Объект.Метаданные() для получения описания конфигурации
  3. 3
    Выполните Реквизиты.Найти("ИмяПоля") и сравните результат с Неопределено
  4. 4
    Если реквизит найден — обращайтесь к полю напрямую, если нет — выполните альтернативную ветку логики
  5. 5
    Проверьте работу на документе, где реквизит есть, и на документе, где его нет

Проверка поля в структуре и соответствии

Структуры широко используются для передачи параметров, хранения настроек и промежуточных результатов. У типа «Структура» есть встроенный метод Свойство(), который проверяет наличие ключа и при необходимости возвращает его значение.

// Простая проверка

Если Параметры.Свойство("Организация") Тогда

Организация = Параметры.Организация;

КонецЕсли;

// Проверка с получением значения

ЗначениеПоля = Неопределено;

Если Параметры.Свойство("Склад", ЗначениеПоля) Тогда

// Ключ есть, значение в переменной ЗначениеПоля

КонецЕсли;

Метод Свойство() возвращает Истина, даже если значение ключа равно Неопределено. Это важное отличие от проверки значения напрямую: ключ может существовать, но быть пустым. Если логика требует именно заполненного поля, проверяйте и наличие ключа, и значение.

Для соответствий применяют метод Получить(): он возвращает Неопределено, если ключ отсутствует. Но здесь есть нюанс — если ключ существует, а значение равно Неопределено, отличить эти ситуации по одному вызову нельзя. В критичных случаях используют перебор ключей соответствия.

Проверка через Попытка…Исключение — когда это оправдано

Конструкция «Попытка…Исключение» позволяет обратиться к полю без предварительной проверки и перехватить ошибку, если поля нет. Этот приём работает с любыми типами данных, включая те, у которых нет метаданных и методов проверки.

Попытка

ЗначениеПоля = Объект.НекоеПоле;

ПолеСуществует = Истина;

Исключение

ПолеСуществует = Ложь;

КонецПопытки;

Однако использовать этот способ как основной не рекомендуется. Во-первых, генерация исключения — ресурсоёмкая операция, и в циклах с большим числом итераций код заметно замедляется. Во-вторых, блок «Исключение» перехватывает не только отсутствие поля, но и любые другие ошибки внутри попытки, что маскирует реальные проблемы. В-третьих, при отладке с включённой остановкой по ошибкам каждое такое исключение будет прерывать выполнение.

Оправданные сценарии для «Попытка…Исключение» — работа с COM-объектами, данными из внешних компонентов и динамически сформированными структурами неизвестного состава, где заранее предсказать набор полей невозможно.

Типичные ошибки
01
Использование Попытка…Исключение в цикле по тысячам строк — резкое падение производительности вместо одной проверки через метаданные
02
Проверка Метаданные().Реквизиты для структуры — у структуры нет метаданных, код падает с ошибкой
03
Сравнение результата Соответствие.Получить() с Неопределено без учёта, что существующий ключ тоже может хранить Неопределено
04
Поиск реквизита табличной части в общей коллекции Реквизиты объекта — реквизиты табличных частей лежат в отдельной коллекции

Проверка поля в запросе и динамических списках

В запросах обращение к несуществующему полю приводит к ошибке компоновки ещё до выполнения. Если текст запроса формируется программно и набор полей зависит от вида объекта, существование поля проверяют до подстановки в текст — тем же способом через метаданные.

МетаданныеДокумента = Метаданные.Документы.РеализацияТоваровУслуг;

Если МетаданныеДокумента.Реквизиты.Найти("Согласовано") <> Неопределено Тогда

ТекстПоля = ", Согласовано";

Иначе

ТекстПоля = "";

КонецЕсли;

ТекстЗапроса = "ВЫБРАТЬ Ссылка" + ТекстПоля + " ИЗ Документ.РеализацияТоваровУслуг";

Отдельный случай — результат запроса. Чтобы проверить, есть ли колонка в выборке, анализируют коллекцию колонок результата: РезультатЗапроса.Колонки.Найти("ИмяПоля"). Для строк дерева значений и таблиц значений колонки проверяются аналогично через коллекцию Колонки.

В динамических списках и СКД состав полей определяется настройками, поэтому программную проверку выполняют через схему компоновки: анализируют наборы данных и поля до обращения к ним в коде расшифровки или обработчиках.

Универсальная функция проверки для разных типов

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

Функция ПолеСуществует(Данные, ИмяПоля) Экспорт

ТипДанных = ТипЗнч(Данные);

Если ТипДанных = Тип("Структура") Тогда

Возврат Данные.Свойство(ИмяПоля);

ИначеЕсли ТипДанных = Тип("Соответствие") Тогда

Для Каждого КлючЗначение Из Данные Цикл

Если КлючЗначение.Ключ = ИмяПоля Тогда

Возврат Истина;

КонецЕсли;

КонецЦикла;

Возврат Ложь;

Иначе

Попытка

Мета = Данные.Метаданные();

Возврат Мета.Реквизиты.Найти(ИмяПоля) <> Неопределено;

Исключение

Возврат Ложь;

КонецПопытки;

КонецЕсли;

КонецФункции

При вызове Метаданные() для ссылок учтите: метод возвращает описание объекта конфигурации без обращения к данным базы, поэтому проверка выполняется быстро и не требует чтения объекта. Это делает её безопасной даже в массовых обработках.

Сравнение способов проверки

Метаданные().Реквизиты.Найти()

Для реквизитов объектов конфигурации. Быстро и надёжно, но не работает со структурами и колонками

Структура.Свойство()

Оптимально для структур: проверяет ключ и возвращает значение. Не применимо к объектам метаданных

Попытка…Исключение

Универсально для любых типов, но медленно и маскирует другие ошибки. Только для исключительных сценариев

Колонки.Найти()

Для таблиц значений, результатов запроса и деревьев. Не проверяет реквизиты объектов

Проверка результата и границы самостоятельной доработки

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

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

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

Итог

Что важно запомнить

Реквизиты объектов проверяют через Метаданные().Реквизиты.Найти(), структуры — методом Свойство(), колонки результатов запросов — через коллекцию Колонки. Попытка…Исключение оставьте для случаев, где других способов нет. Всегда тестируйте обе ветки: с полем и без него.

Частые вопросы

Как проверить, есть ли реквизит у строки табличной части?

Через метаданные объекта: получите описание табличной части Метаданные().ТабличныеЧасти.Найти("ИмяТЧ"), затем в её коллекции Реквизиты выполните Найти("ИмяРеквизита"). Проверять нужно по метаданным объекта, а не по конкретной строке.

Почему Структура.Свойство() возвращает Истина, хотя значения нет?

Метод проверяет наличие ключа, а не заполненность. Если структура создана с ключом без значения или со значением Неопределено, Свойство() вернёт Истина. Для проверки заполненности дополнительно анализируйте значение через второй параметр метода.

Можно ли проверить существование стандартного реквизита, например «Дата» или «Номер»?

Стандартные реквизиты не входят в коллекцию Реквизиты — они доступны через коллекцию СтандартныеРеквизиты. На практике проверять их обычно не нужно: состав стандартных реквизитов фиксирован типом объекта.

Как проверить поле в данных, полученных из JSON или XML?

После чтения данные обычно преобразуются в структуру или соответствие. Для структуры используйте Свойство(), для соответствия — Получить() с учётом нюанса с Неопределено. Если данные читаются через ЧтениеJSON потоково, проверяйте имя текущего свойства в цикле чтения.

Влияет ли проверка через метаданные на производительность?

Сам вызов Метаданные() и поиск в коллекции выполняются быстро. В массовых циклах оптимально вынести получение метаданных и результат поиска за пределы цикла, проверив поле один раз до начала обхода данных.

Что делать, если код должен работать в разных конфигурациях с разным составом реквизитов?

Вынесите проверку в отдельную функцию общего модуля и вызывайте её перед каждым обращением к необязательному реквизиту. Для значений по умолчанию используйте ветку «Иначе», чтобы логика не прерывалась при отсутствии поля в конкретной конфигурации.