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

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

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

Способы проверить наличие реквизита у объекта 1С в БСП: методы Метаданные(), Найти, ОбщегоНазначения, примеры кода, типичные ошибки и FAQ для разработчиков.

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

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

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

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

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

Классический пример — подсистема «Дополнительные отчеты и обработки», где внешний код получает ссылку неизвестного типа. Другой случай — универсальная выгрузка в XML или JSON, когда нужно обойти все реквизиты объекта, но пропустить те, которых нет в конкретной версии конфигурации после обновления.

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

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

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

Пример для объекта (набора данных, полученного через ПолучитьОбъект()):

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

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

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

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

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

Проверка стандартных реквизитов

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

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

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

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

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

КонецЕсли;

КонецЦикла;

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

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

Типовые средства БСП: модуль ОбщегоНазначения

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

Ключевые инструменты модуля ОбщегоНазначения:

  • ОбщегоНазначения.ЕстьРеквизитОбъекта(ИмяРеквизита, МетаданныеОбъекта) — проверяет наличие реквизита по объекту метаданных, возвращает Истина или Ложь;
  • ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Ссылка, ИмяРеквизита) — безопасно читает значение реквизита по ссылке без получения объекта целиком;
  • ОбщегоНазначения.ЗначенияРеквизитовОбъекта(Ссылка, "Реквизит1,Реквизит2") — читает сразу несколько реквизитов одним запросом.

Пример проверки перед обращением:

МетаданныеДокумента = Ссылка.Метаданные();

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

Организация = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Ссылка, "Организация");

КонецЕсли;

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

bsl
Если ОбщегоНазначения.ЕстьРеквизитОбъекта("Ответственный", Ссылка.Метаданные()) Тогда
	Ответственный = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Ссылка, "Ответственный");
КонецЕсли;

Альтернативные способы проверки

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

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

Проверка через запрос

В запросах обращение к несуществующему реквизиту приведёт к ошибке ещё на этапе выполнения запроса. Поэтому текст запроса для универсальных механизмов формируют динамически: сначала проверяют наличие реквизита через метаданные, потом добавляют поле в текст запроса. Если реквизита нет, в запрос подставляют NULL или НЕОПРЕДЕЛЕНО вместо имени поля.

Коллекция реквизитов управляемой формы

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

Сравнение вариантов

Метаданные + Найти()

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

ОбщегоНазначения.ЕстьРеквизитОбъекта

Рекомендуемый вариант в конфигурациях на БСП. Короткий вызов, но нужен объект метаданных вторым параметром.

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

Допустим только как крайняя мера в разовом коде. Медленно в циклах и маскирует другие ошибки.

Запрос с динамическим текстом

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

Как проверить результат и не ошибиться

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

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

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

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

Вызов ЕстьРеквизитОбъекта
Норма

Возвращает Истина для существующего реквизита и Ложь для отсутствующего

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

Всегда Ложь — вероятно, передана ссылка вместо объекта метаданных

Стандартные реквизиты
Норма

Код, Наименование, Дата определяются через СтандартныеРеквизиты

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

Поиск стандартного реквизита через коллекцию Реквизиты возвращает Неопределено

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

Метаданные получены один раз до цикла, проверка внутри цикла мгновенная

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

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

Типичные ошибки при проверке реквизитов

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

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

Третья ошибка — получение объекта через ПолучитьОбъект() только ради проверки реквизита. Это лишнее чтение из базы: метаданные доступны и у ссылки.

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

Ограничения и границы применения

Проверка через метаданные отвечает на вопрос «описан ли реквизит в конфигурации», но не гарантирует, что значение заполнено. Реквизит может существовать и при этом содержать пустое значение — для этого нужна отдельная проверка через ЗначениеЗаполнено().

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

Итог

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

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

Часто задаваемые вопросы

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

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

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

Потому что Дата — стандартный реквизит, а коллекция Реквизиты содержит только реквизиты, добавленные разработчиком. Стандартные реквизиты проверяйте перебором коллекции СтандартныеРеквизиты объекта метаданных.

Можно ли проверить реквизит табличной части функцией БСП?

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

Что быстрее: проверка через метаданные или Попытка/Исключение?

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

Как безопасно прочитать значение реквизита, которого может не быть?

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

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

Да, если расширение подключено и активно в текущем сеансе, его реквизиты присутствуют в коллекции Реквизиты объекта метаданных. Если расширение отключено, проверка корректно вернёт Ложь.