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

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

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

Способы проверить наличие реквизита у объекта 1С: метод Найти, метаданные, универсальная функция с примерами кода и разбором типичных ошибок.

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

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

Основной способ: поиск реквизита через метаданные объекта

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

Типовой фрагмент кода выглядит так:

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

// реквизит существует, можно обращаться

Значение = Объект.Комментарий;

Иначе

// реквизита нет

КонецЕсли;

Метод Найти() возвращает объект описания реквизита, если он найден, и Неопределено — если такого реквизита в конфигурации нет. Сравнение с Неопределено — это и есть проверка существования.

bsl
Функция ЕстьРеквизит(Объект, ИмяРеквизита)
    Возврат Объект.Метаданные().Реквизиты.Найти(ИмяРеквизита) <> Неопределено;
КонецФункции

Универсальная функция проверки для любого объекта

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

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

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

МетаданныеОбъекта = СсылкаИлиОбъект.Метаданные();

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

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

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

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

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

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

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

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

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

// реквизит табличной части существует

КонецЕсли;

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

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

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

У регистров сведений и накопления структура иная: там есть коллекции Измерения, Ресурсы и Реквизиты. Универсальная функция для регистра должна искать во всех трёх коллекциях либо принимать параметр, указывающий, где искать.

Где искать поле

Реквизиты

Реквизиты шапки справочника, документа, задачи

СтандартныеРеквизиты

Системные поля: Ссылка, Номер, Дата, Проведен, Код

ТабличныеЧасти.Найти().Реквизиты

Колонки табличных частей объекта

Измерения и Ресурсы

Поля регистров сведений и накопления

Альтернатива: проверка через Попытка/Исключение

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

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

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

Проверка результата и отладка

Чтобы убедиться, что функция работает корректно, проверьте её на трёх наборах данных: объекте, где реквизит точно есть; объекте, где его нет; объекте другого типа. Все три вызова должны вернуть ожидаемые значения без исключений.

Для быстрой отладки удобно вывести состав реквизитов объекта в сообщения:

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

Сообщить(Реквизит.Имя);

КонецЦикла;

Такой цикл показывает реальный состав реквизитов и помогает найти опечатку в имени — самую частую причину «несуществующего» реквизита.

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

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

Реквизит существует в конфигураторе
Норма

Найти() возвращает объект описания, значение не Неопределено

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

Возвращается Неопределено — проверьте опечатки в имени

Имя реквизита в коде
Норма

Совпадает с именем в конфигураторе посимвольно

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

Лишние пробелы, другой регистр или транслитерация

Тип проверяемого значения
Норма

Это ссылка или объект данных с методом Метаданные()

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

Передана строка, число или Неопределено — будет ошибка вызова метода

Границы применения и производительность

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

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

Итог

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

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

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

Можно ли проверить реквизит у строки табличной части напрямую?

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

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

Номер — стандартный реквизит, он находится в коллекции СтандартныеРеквизиты, а не Реквизиты. Для системных полей используйте соответствующую коллекцию метаданных.

Работает ли проверка на тонком клиенте и в веб-клиенте?

Да, доступ к метаданным через Метаданные() и глобальный контекст Метаданные работает на клиенте в управляемом приложении. Однако серверные вызовы всё равно предпочтительнее для массовых операций.

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

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

Чем отличается проверка существования от проверки заполненности?

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

Есть ли в типовых конфигурациях готовая функция проверки?

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