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

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

Как проверить, что у объекта есть реквизит в 1С

Способы проверить наличие реквизита у объекта 1С: ЕстьРеквизитОбъекта, метаданные, структура. Примеры кода, типичные ошибки и рекомендации для разработчиков.

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

Способов проверки несколько: через метаданные объекта, через функцию общих модулей БСП ЕстьРеквизитОбъекта, через структуру и метод ЗаполнитьЗначенияСвойств, через попытку обращения в Попытка...Исключение. Выбор зависит от того, что именно проверяется — реквизит справочника, колонка табличной части, свойство структуры или поле запроса.

Материал разбирает каждый способ с примерами кода, ограничениями и типичными ошибками, чтобы проверка работала надёжно и не замедляла массовые операции.

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

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

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

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

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

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

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

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

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

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

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

КонецЕсли;

Для Каждого СтандартныйРеквизит Из МетаданныеОбъекта.СтандартныеРеквизиты Цикл

Если СтандартныйРеквизит.Имя = ИмяРеквизита Тогда

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

КонецЕсли;

КонецЦикла;

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

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

Функция ЕстьРеквизитОбъекта из БСП

В конфигурациях на базе Библиотеки стандартных подсистем (УТ, ERP, БП, ЗУП) уже есть готовая функция ОбщегоНазначения.ЕстьРеквизитОбъекта(ИмяРеквизита, МетаданныеОбъекта). Она возвращает Истина или Ложь и учитывает как обычные, так и стандартные реквизиты, а также реквизиты, общие для группы объектов.

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

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

КонецЕсли;

Обратите внимание на порядок параметров: сначала имя реквизита строкой, затем объект метаданных. Частая ошибка — передать туда сам объект или ссылку вместо Метаданные(), из-за чего функция отрабатывает некорректно. Перед использованием проверьте сигнатуру в своей версии БСП — в старых релизах порядок параметров отличался.

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

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

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

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

МетаданныеТЧ = МетаданныеОбъекта.ТабличныеЧасти.Найти("Товары");

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

И МетаданныеТЧ.Реквизиты.Найти("Скидка") <> Неопределено Тогда

// колонка "Скидка" существует

КонецЕсли;

Для таблицы значений, построенной в коде (результат запроса, загруженный файл), метаданных нет — там проверяют колонки через Таблица.Колонки.Найти("ИмяКолонки"). Это типичный сценарий при загрузке данных из Excel, когда состав колонок файла может меняться.

Для строки дерева значений или произвольной структуры подход другой: у структуры есть метод Свойство("Имя", НайденноеЗначение), который вернёт Истина, если ключ существует. Это самый быстрый способ проверки в горячих циклах, потому что он не обращается к конфигурации вообще.

Порядок действий для универсальной проверки
  1. 1
    Определите тип проверяемого: объект конфигурации, табличная часть, таблица значений или структура
  2. 2
    Для объекта конфигурации получите Метаданные() и выполните Реквизиты.Найти(Имя)
  3. 3
    Добавьте поиск в СтандартныеРеквизиты, если имя может быть системным (Код, Наименование, Дата)
  4. 4
    Для табличной части сначала проверьте наличие самой ТЧ, затем реквизита внутри неё
  5. 5
    Для структуры используйте метод Свойство(), для таблицы значений — Колонки.Найти()
  6. 6
    Проверьте результат на тестовом объекте, где реквизит есть, и на объекте, где его нет

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

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

Проверяемые = Новый Структура("Организация, ДоговорКонтрагента, СкидкаНаценка");

ЗаполнитьЗначенияСвойств(Проверяемые, ДокументОбъект);

Если Проверяемые.ДоговорКонтрагента <> Неопределено Тогда

// реквизит есть и заполнен

КонецЕсли;

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

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

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

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

БСП ЕстьРеквизитОбъекта

Готовое решение с учётом стандартных реквизитов. Доступно только в конфигурациях на БСП

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

Самый быстрый вариант для структур и соответствий, не работает с объектами конфигурации напрямую

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

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

Почему не стоит проверять через Попытка...Исключение

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

Допустимый сценарий для Попытка — обращение к свойству объекта внешней компоненты или COM-объекта, где метаданных платформы нет и другого способа проверить состав свойств не существует. Для штатных объектов 1С всегда используйте метаданные.

Типичные ошибки
01
Поиск стандартного реквизита (Код, Дата, Номер) в коллекции Реквизиты — его там нет, проверка всегда вернёт Ложь
02
Передача ссылки вместо Метаданные() в функцию БСП — функция получает не тот тип и работает некорректно
03
Проверка реквизита в цикле без кэширования результата — метаданные одни и те же, а поиск выполняется тысячи раз
04
Использование Попытка...Исключение как основного способа — медленно и маскирует другие ошибки
05
Сравнение имени реквизита с учётом регистра в нестрогих местах — в 1С имена регистронезависимы, но лишние пробелы в строке имени ломают поиск

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

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

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

В обменах между конфигурациями с разным составом реквизитов удобно один раз построить соответствие «имя реквизита — есть/нет» для каждого типа объекта и передавать его в процедуры заполнения. Это убирает сотни повторных обращений к метаданным и делает код заметно чище.
ПЗ
Практическое замечание

Частые сценарии: расширения, обмены, универсальные обработки

Расширение конфигурации

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

Обмен между разными конфигурациями

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

Универсальная печатная форма или отчёт

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

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

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

Функция возвращает Истина для заведомо существующего реквизита
Норма

Имя найдено в коллекции метаданных

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

Возвращается Ложь — проверьте опечатки и пробелы в имени

Проверка стандартного реквизита (Код, Дата)
Норма

Находится через СтандартныеРеквизиты

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

Не найден — поиск идёт только в обычных Реквизитах

Работа в цикле по объектам
Норма

Проверка выполнена один раз до цикла

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

Метаданные запрашиваются на каждой итерации

Поведение при отсутствии реквизита
Норма

Выполняется запасная ветка кода без ошибки

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

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

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

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

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

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

Дата, Номер, Код, Наименование, Проведен и Ссылка — стандартные реквизиты. Они хранятся в коллекции СтандартныеРеквизиты объекта метаданных, и искать их нужно там. Функция ЕстьРеквизитОбъекта из БСП учитывает обе коллекции автоматически.

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

У результата запроса после выгрузки в таблицу значений используйте Выборка.Владелец().Колонки.Найти("Имя") или проверяйте колонки самой таблицы. Если работаете с выборкой напрямую, безопаснее сразу выгрузить результат и анализировать колонки таблицы значений.

Можно ли проверить реквизит по синониму, а не по имени?

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

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

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

Итог

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

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