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