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