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

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

Как проверить наличие реквизита в 1С

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

Проверка существования реквизита перед обращением к нему — стандартная задача при разработке универсальных механизмов в 1С. Она нужна, когда один и тот же код должен работать с разными видами справочников или документов, состав реквизитов которых заранее неизвестен, либо когда конфигурация дорабатывается и реквизит может отсутствовать в части баз.

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

Существует несколько рабочих способов: проверка через коллекцию метаданных, поиск в структуре, обработка исключения через «Попытка», а также отдельные приёмы для табличных частей, дополнительных реквизитов и динамических списков. Ниже разобраны все варианты с примерами кода и рекомендациями по выбору.

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

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

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

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

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

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

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

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

ДокументОбъект.Комментарий = "Заполнено автоматически";

КонецЕсли;

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

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

Проверка реквизита табличной части

Табличные части имеют собственную коллекцию реквизитов, поэтому проверка выполняется в два шага: сначала убеждаемся, что табличная часть существует, затем ищем реквизит внутри неё.

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

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

МетаданныеТЧ = МетаданныеОбъекта.ТабличныеЧасти.Найти(ИмяТЧ);

Если МетаданныеТЧ = Неопределено Тогда

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

КонецЕсли;

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

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

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

Проверка через структуру и заполнение значений

Когда данные находятся не в объекте базы, а в структуре (например, результат разбора JSON или параметры процедуры), используйте метод Свойство(). Он возвращает Истина, если ключ существует, и может сразу вернуть значение через второй параметр.

ЗначениеРеквизита = Неопределено;

Если СтруктураДанных.Свойство("Артикул", ЗначениеРеквизита) Тогда

// Ключ есть, значение уже в переменной ЗначениеРеквизита

Иначе

// Ключа нет — используем значение по умолчанию

КонецЕсли;

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

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

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

Основной способ для объектов базы. Быстро, предсказуемо, но не покрывает стандартные реквизиты.

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

Для структур и соответствий. Сразу возвращает значение, не работает с объектами метаданных.

ЗаполнитьЗначенияСвойств

Когда нужно прочитать пакет реквизитов за один вызов. Требует подготовки структуры-приёмника.

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

Универсально, но медленно и маскирует другие ошибки. Только как крайняя мера.

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

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

ЗначениеРеквизита = Неопределено;

Попытка

ЗначениеРеквизита = Объект.НекийРеквизит;

Исключение

// Реквизита нет либо произошла другая ошибка

ЗначениеРеквизита = Неопределено;

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

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

Проверка дополнительных реквизитов и сведений

Дополнительные реквизиты, которые пользователь добавляет через механизм БСП «Дополнительные реквизиты и сведения», не входят в метаданные объекта — они хранятся в табличной части ДополнительныеРеквизиты или в регистре сведений ДополнительныеСведения. Проверка через Метаданные().Реквизиты их не найдёт.

Для табличной части дополнительных реквизитов поиск выполняется по ссылке на свойство:

ПараметрыОтбора = Новый Структура("Свойство", СсылкаНаСвойство);

НайденныеСтроки = Объект.ДополнительныеРеквизиты.НайтиСтроки(ПараметрыОтбора);

Если НайденныеСтроки.Количество() > 0 Тогда

ЗначениеСвойства = НайденныеСтроки[0].Значение;

КонецЕсли;

Имя нужного свойства удобнее получать через функциональность БСП, например через модуль УправлениеСвойствами (в старых версиях — РаботаСДополнительнымиРеквизитами), а не искать по синониму: синонимы пользователи могут переименовать, и код перестанет находить свойство.

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

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

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

ПоляЗапроса = "Ссылка, Дата";

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

ПоляЗапроса = ПоляЗапроса + ", Склад";

КонецЕсли;

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

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

Типичные ошибки
01
Поиск стандартного реквизита (Код, Наименование) в коллекции Реквизиты — он там отсутствует, проверка всегда вернёт Неопределено.
02
Обращение к реквизиту табличной части без проверки существования самой табличной части — ошибка при работе с другими видами документов.
03
Поиск дополнительного реквизита по синониму — пользователь переименует свойство, и код перестанет работать.
04
Проверка через Попытку внутри цикла по тысячам объектов — массовая обработка замедляется в разы.
05
Проверка реквизита у объекта одного вида и использование результата для другого вида — состав реквизитов различается.

Производительность и кэширование проверок

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

КэшРеквизитов = Новый Соответствие;

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

Ключ = Объект.Метаданные().Имя + "." + ИмяРеквизита;

Результат = КэшРеквизитов[Ключ];

Если Результат = Неопределено Тогда

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

КэшРеквизитов.Вставить(Ключ, Результат);

КонецЕсли;

Возврат Результат;

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

Такой кэш особенно эффективен в обменах данными и пакетных обработках, где один и тот же вид документа обходится многократно. Важно, чтобы ключ кэша включал имя вида объекта, иначе проверка для справочника «Номенклатура» ошибочно применится к справочнику «Контрагенты».

Контрольные точки

Как проверить результат

Код отрабатывает на объекте с реквизитом
Норма

Значение прочитано или записано без ошибок

Тревожный признак

Ошибка «Поле объекта не обнаружено»

Код отрабатывает на объекте без реквизита
Норма

Выполняется ветка «Иначе», ошибки нет

Тревожный признак

Исключение прерывает обработку

Массовая обработка
Норма

Время выполнения сопоставимо с обычным обходом

Тревожный признак

Резкое замедление из-за исключений в цикле

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

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

У ссылки тоже есть метод Метаданные(), поэтому проверка выглядит так же: Ссылка.Метаданные().Реквизиты.Найти("Имя"). Но чтобы прочитать значение реквизита, объект получать не обязательно — достаточно запроса или обращения «через точку», которое платформа сама преобразует в запрос.

Почему Найти() возвращает Неопределено, хотя реквизит точно есть?

Чаще всего ищут стандартный реквизит (Код, Наименование, Дата) в коллекции Реквизиты — он там не хранится. Также проверьте точное имя: поиск чувствителен к написанию, а лишний пробел или опечатка дадут отрицательный результат.

Можно ли проверить наличие реквизита у формы, а не у объекта?

Для реквизитов управляемой формы обращайтесь к ним как к свойствам формы через ЭтаФорма, но проверять их наличие обычно не требуется — состав реквизитов формы фиксирован. Если форма динамическая, используйте попытку обращения или храните список созданных реквизитов в отдельной переменной.

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

У строки табличной части нет метода Метаданные(). Проверяйте через метаданные владельца: Объект.Метаданные().ТабличныеЧасти[ИмяТЧ].Реквизиты.Найти(Имя). Либо используйте ЗаполнитьЗначенияСвойств со структурой-приёмником — отсутствующие колонки просто не заполнятся.

Что быстрее: Найти() по метаданным или Попытка?

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

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

Да. Реквизиты, добавленные расширением, включаются в коллекцию метаданных после подключения расширения, и Найти() их обнаруживает. Если расширение отключено, проверка корректно вернёт Неопределено — это удобный способ писать код, устойчивый к отключению расширений.

Итог

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

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