Разработка и Конфигурация · 12 мин
Как проверить, что у объекта есть реквизит в 1С
Способы проверить наличие реквизита у объекта 1С: ЕстьРеквизитОбъекта, метаданные, структура. Примеры кода, типичные ошибки и рекомендации для разработчиков.
Задача проверить, есть ли реквизит у объекта, возникает в 1С постоянно: при обмене данными между конфигурациями, при написании универсальных обработчиков, при работе с расширениями, где реквизит может присутствовать или отсутствовать в зависимости от релиза. Обращение к несуществующему реквизиту напрямую через точку вызывает ошибку «Поле объекта не обнаружено», и в рабочей базе это означает падение обмена или отчёта у пользователя.
Способов проверки несколько: через метаданные объекта, через функцию общих модулей БСП ЕстьРеквизитОбъекта, через структуру и метод ЗаполнитьЗначенияСвойств, через попытку обращения в Попытка...Исключение. Выбор зависит от того, что именно проверяется — реквизит справочника, колонка табличной части, свойство структуры или поле запроса.
Материал разбирает каждый способ с примерами кода, ограничениями и типичными ошибками, чтобы проверка работала надёжно и не замедляла массовые операции.
Проверка через метаданные объекта
Базовый и самый надёжный способ — обратиться к описанию конфигурации через метод Метаданные(). У любого ссылочного объекта (справочника, документа, плана счетов) есть коллекция Реквизиты, в которой метод Найти() ищет реквизит по имени. Если реквизит не найден, метод возвращает Неопределено, и ошибки не возникает.
Функция ЕстьРеквизит(Объект, ИмяРеквизита)
МетаданныеОбъекта = Объект.Метаданные();
Возврат МетаданныеОбъекта.Реквизиты.Найти(ИмяРеквизита) <> Неопределено;
КонецФункции
Важно понимать ограничение: коллекция Реквизиты содержит только «собственные» реквизиты, добавленные в конфигураторе. Стандартные реквизиты — Ссылка, Код, Наименование, Дата, Номер, Проведен — лежат в отдельной коллекции СтандартныеРеквизиты, и проверять их нужно отдельно. Если универсальная функция должна принимать и стандартные имена, добавьте второй поиск.
Функция ЕстьРеквизитПолная(Объект, ИмяРеквизита)
МетаданныеОбъекта = Объект.Метаданные();
Если МетаданныеОбъекта.Реквизиты.Найти(ИмяРеквизита) <> Неопределено Тогда
Возврат Истина;
КонецЕсли;
Для Каждого СтандартныйРеквизит Из МетаданныеОбъекта.СтандартныеРеквизиты Цикл
Если СтандартныйРеквизит.Имя = ИмяРеквизита Тогда
Возврат Истина;
КонецЕсли;
КонецЦикла;
Возврат Ложь;
КонецФункции
Функция ЕстьРеквизитОбъекта из БСП
В конфигурациях на базе Библиотеки стандартных подсистем (УТ, ERP, БП, ЗУП) уже есть готовая функция ОбщегоНазначения.ЕстьРеквизитОбъекта(ИмяРеквизита, МетаданныеОбъекта). Она возвращает Истина или Ложь и учитывает как обычные, так и стандартные реквизиты, а также реквизиты, общие для группы объектов.
Если ОбщегоНазначения.ЕстьРеквизитОбъекта("Комментарий", ДокументОбъект.Метаданные()) Тогда
ДокументОбъект.Комментарий = "Заполнено обработкой";
КонецЕсли;
Обратите внимание на порядок параметров: сначала имя реквизита строкой, затем объект метаданных. Частая ошибка — передать туда сам объект или ссылку вместо Метаданные(), из-за чего функция отрабатывает некорректно. Перед использованием проверьте сигнатуру в своей версии БСП — в старых релизах порядок параметров отличался.
Если конфигурация самописная и БСП в ней нет, функцию легко воспроизвести самостоятельно по образцу из первого раздела — внутри неё лежит именно поиск по коллекции метаданных.
Проверка реквизита табличной части и колонки таблицы значений
Для табличных частей логика та же, но путь длиннее: сначала находим табличную часть, потом её реквизит. Проверять стоит оба уровня, потому что обращение к несуществующей табличной части тоже вызовет ошибку.
МетаданныеОбъекта = ДокументОбъект.Метаданные();
МетаданныеТЧ = МетаданныеОбъекта.ТабличныеЧасти.Найти("Товары");
Если МетаданныеТЧ <> Неопределено
И МетаданныеТЧ.Реквизиты.Найти("Скидка") <> Неопределено Тогда
// колонка "Скидка" существует
КонецЕсли;
Для таблицы значений, построенной в коде (результат запроса, загруженный файл), метаданных нет — там проверяют колонки через Таблица.Колонки.Найти("ИмяКолонки"). Это типичный сценарий при загрузке данных из Excel, когда состав колонок файла может меняться.
Для строки дерева значений или произвольной структуры подход другой: у структуры есть метод Свойство("Имя", НайденноеЗначение), который вернёт Истина, если ключ существует. Это самый быстрый способ проверки в горячих циклах, потому что он не обращается к конфигурации вообще.
- 1Определите тип проверяемого: объект конфигурации, табличная часть, таблица значений или структура
- 2Для объекта конфигурации получите Метаданные() и выполните Реквизиты.Найти(Имя)
- 3Добавьте поиск в СтандартныеРеквизиты, если имя может быть системным (Код, Наименование, Дата)
- 4Для табличной части сначала проверьте наличие самой ТЧ, затем реквизита внутри неё
- 5Для структуры используйте метод Свойство(), для таблицы значений — Колонки.Найти()
- 6Проверьте результат на тестовом объекте, где реквизит есть, и на объекте, где его нет
Проверка через ЗаполнитьЗначенияСвойств и структуру
Когда нужно не просто проверить один реквизит, а безопасно перенести набор полей из структуры в объект, удобнее обратный приём: сформировать структуру с именами ожидаемых реквизитов и пустыми значениями, вызвать ЗаполнитьЗначенияСвойств(Структура, Объект) — платформа заполнит в структуре только те ключи, которые реально существуют у объекта. Ключи, которых нет, останутся со значением Неопределено.
Проверяемые = Новый Структура("Организация, ДоговорКонтрагента, СкидкаНаценка");
ЗаполнитьЗначенияСвойств(Проверяемые, ДокументОбъект);
Если Проверяемые.ДоговорКонтрагента <> Неопределено Тогда
// реквизит есть и заполнен
КонецЕсли;
У приёма есть тонкость: он не отличает «реквизита нет» от «реквизит есть, но пустой», если тип реквизита допускает неопределённое значение. Поэтому для строгой проверки существования надёжнее метаданные, а ЗаполнитьЗначенияСвойств используйте именно для массового безопасного чтения значений.
Сравнение способов проверки
Точная проверка существования. Подходит для объектов конфигурации, требует отдельной обработки стандартных реквизитов
Готовое решение с учётом стандартных реквизитов. Доступно только в конфигурациях на БСП
Самый быстрый вариант для структур и соответствий, не работает с объектами конфигурации напрямую
Универсально, но медленно и маскирует другие ошибки. Допустимо только как последний вариант
Почему не стоит проверять через Попытка...Исключение
Соблазнительно просто обратиться к реквизиту внутри Попытка и считать исключение признаком его отсутствия. Технически это работает, но у подхода три серьёзных недостатка. Во-первых, генерация исключения — дорогая операция, и в цикле по тысячам объектов обмен заметно замедлится. Во-вторых, исключение может возникнуть по другой причине — например, из-за ошибки в модуле объекта при обращении к свойству — и вы примете её за отсутствие реквизита. В-третьих, такой код тяжело отлаживать: при включённой остановке по ошибке отладчик будет постоянно срабатывать.
Допустимый сценарий для Попытка — обращение к свойству объекта внешней компоненты или COM-объекта, где метаданных платформы нет и другого способа проверить состав свойств не существует. Для штатных объектов 1С всегда используйте метаданные.
Производительность и кэширование результата
Обращение к метаданным быстрое, но не бесплатное. Если проверка выполняется внутри цикла обработки документов, правильнее вынести её за пределы цикла: состав реквизитов у всех документов одного вида одинаков, поэтому достаточно проверить один раз по метаданным менеджера объекта, например Метаданные.Документы.РеализацияТоваровУслуг.Реквизиты.Найти(...), и дальше использовать сохранённый флаг.
В универсальных механизмах, где тип объекта заранее неизвестен, применяют кэш в виде соответствия: ключ — полное имя объекта метаданных, значение — структура с признаками наличия нужных реквизитов. Именно так устроены проверки в типовых механизмах обмена, где одни и те же свойства проверяются для сотен видов документов.
В обменах между конфигурациями с разным составом реквизитов удобно один раз построить соответствие «имя реквизита — есть/нет» для каждого типа объекта и передавать его в процедуры заполнения. Это убирает сотни повторных обращений к метаданным и делает код заметно чище.
Частые сценарии: расширения, обмены, универсальные обработки
Расширение конфигурации
В расширении нельзя быть уверенным, что реквизит основной конфигурации существует во всех поддерживаемых релизах. Перед обращением к нему выполняйте проверку через метаданные и предусмотрите ветку поведения на случай отсутствия — иначе обновление основной конфигурации сломает расширение в рабочей базе.
Обмен между разными конфигурациями
При выгрузке из одной конфигурации и загрузке в другую состав реквизитов почти всегда различается. Проверка наличия реквизита перед записью значения — обязательный элемент правил конвертации, без него обмен упадёт на первом же документе с «лишним» полем.
Универсальная печатная форма или отчёт
Если обработка должна работать с любым документом, проверяйте каждый используемый реквизит и подставляйте значение по умолчанию при его отсутствии. Это дешевле, чем разбирать ошибки у пользователей на документах, где поля нет.
Как проверить результат
Имя найдено в коллекции метаданных
Возвращается Ложь — проверьте опечатки и пробелы в имени
Находится через СтандартныеРеквизиты
Не найден — поиск идёт только в обычных Реквизитах
Проверка выполнена один раз до цикла
Метаданные запрашиваются на каждой итерации
Выполняется запасная ветка кода без ошибки
Возникает «Поле объекта не обнаружено»
Частые вопросы
Как проверить наличие реквизита у ссылки, не получая объект?
Метаданные доступны и у ссылки: Ссылка.Метаданные().Реквизиты.Найти("Имя"). Получать объект методом ПолучитьОбъект() не нужно — это лишнее чтение из базы. Проверка существования реквизита работает со схемой конфигурации, а не с данными.
Почему Реквизиты.Найти("Дата") возвращает Неопределено, хотя поле есть?
Дата, Номер, Код, Наименование, Проведен и Ссылка — стандартные реквизиты. Они хранятся в коллекции СтандартныеРеквизиты объекта метаданных, и искать их нужно там. Функция ЕстьРеквизитОбъекта из БСП учитывает обе коллекции автоматически.
Как проверить наличие колонки в результате запроса?
У результата запроса после выгрузки в таблицу значений используйте Выборка.Владелец().Колонки.Найти("Имя") или проверяйте колонки самой таблицы. Если работаете с выборкой напрямую, безопаснее сразу выгрузить результат и анализировать колонки таблицы значений.
Можно ли проверить реквизит по синониму, а не по имени?
Технически коллекцию метаданных можно перебрать и сравнить свойство Синоним каждого реквизита, но делать этого не стоит: синонимы могут совпадать у разных реквизитов и меняются при доработках. Всегда проверяйте и обращайтесь к реквизиту по имени — оно уникально внутри объекта.
Работает ли проверка для реквизитов, добавленных расширением?
Да. После применения расширения добавленные им реквизиты становятся частью метаданных сеанса, и Реквизиты.Найти() их находит. Но если расширение отключат, проверка вернёт Ложь — код должен корректно обрабатывать оба случая.
Что важно запомнить
Наличие реквизита проверяется через метаданные: Реквизиты.Найти() для обычных и СтандартныеРеквизиты для системных полей. В конфигурациях на БСП используйте готовую ЕстьРеквизитОбъекта, для структур — метод Свойство(). Не проверяйте через Попытка...Исключение и выносите проверку за пределы циклов.