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

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

Как проверить наличие поля объекта в 1С

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

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

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

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

Какие объекты и поля бывают в 1С

Прежде чем выбирать способ проверки, нужно понять, с каким объектом вы работаете. В 1С поля (реквизиты) существуют у нескольких разных видов сущностей, и механизм проверки у них различается.

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

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

Третий вид — данные, полученные извне: результат запроса, строка табличной части, выборка. Для них источником истины служит либо запрос (какие поля выбраны), либо метаданные табличной части.

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

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

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

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

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

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

Если у вас нет самого объекта, а есть только его тип или имя вида, метаданные можно получить иначе:

// По имени вида объекта

МетаДок = Метаданные.Документы.Найти("РеализацияТоваровУслуг");

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

ЕстьПоле = МетаДок.Реквизиты.Найти("СуммаДокумента") <> Неопределено;

КонецЕсли;

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

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

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

МетаДок = Метаданные.Документы.Найти("РеализацияТоваровУслуг");

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

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

ЕстьКолонка = МетаТЧ.Реквизиты.Найти("СтавкаНДС") <> Неопределено;

КонецЕсли;

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

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

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

У структур метаданных нет, поэтому используется штатный метод Свойство(). Он возвращает Истина, если ключ существует, и может сразу вернуть значение через второй параметр:

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

Значение = Неопределено;

Если Параметры.Свойство("Организация", Значение) Тогда

// ключ есть, значение получено

КонецЕсли;

Для таблицы значений проверяют наличие колонки через коллекцию Колонки:

Если ТаблицаДанных.Колонки.Найти("СуммаНДС") <> Неопределено Тогда

// колонка существует

КонецЕсли;

Тот же подход работает для результата запроса: у объекта «РезультатЗапроса» есть коллекция Колонки, и проверить, вернул ли запрос нужное поле, можно до начала обхода выборки. Это удобно в универсальных обработках, где текст запроса формируется динамически.

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

Проверка через попытку и исключение

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

Попытка

Значение = Объект.НекийРеквизит;

ПолеЕсть = Истина;

Исключение

ПолеЕсть = Ложь;

КонецПопытки;

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

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

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

Каждый метод имеет свою область применения. Выбор зависит от типа проверяемого объекта и требований к производительности.

СпособГде применимОграничения
Метаданные + Реквизиты.Найти()Справочники, документы, другие прикладные объектыНе показывает стандартные реквизиты
Структура.Свойство()Структуры и фиксированные структурыТолько для коллекций типа Структура
Колонки.Найти()Таблицы значений, результаты запросовПроверяет колонку, а не значение в строке
Попытка/ИсключениеОбъекты неизвестного типаМедленно, скрывает другие ошибки

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

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

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

Метод Свойство()

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

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

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

Типичные ошибки при проверке полей

Первая распространённая ошибка — проверка значения вместо проверки наличия поля. Код вида Если Объект.Реквизит <> Неопределено не проверяет существование реквизита: если реквизита нет, произойдёт исключение ещё до сравнения. Сначала проверяется наличие поля, потом читается значение.

Вторая ошибка — поиск стандартного реквизита в коллекции Реквизиты. Поля Ссылка, Код, Наименование, Дата там отсутствуют, и проверка вернёт ложный отрицательный результат. Для них нужна коллекция СтандартныеРеквизиты.

Третья ошибка — кэширование результата проверки без учёта контекста. Если обработка работает с разными видами документов, результат проверки для одного вида нельзя применять к другому: состав реквизитов у них разный.

Четвёртая ошибка — игнорирование регистра имён. Во встроенном языке 1С имена реквизитов нечувствительны к регистру, но при сравнении строк вручную (например, при обходе коллекции метаданных через цикл) лучше приводить имена к одному регистру функцией ВРег(), чтобы избежать расхождений в логике.

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

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

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

Полезный приём для диагностики — вывести полный список реквизитов объекта. Это помогает понять, как на самом деле называется нужное поле, особенно если конфигурация незнакомая:

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

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

КонецЦикла;

В конфигураторе проверку удобно выполнять через табло (Ctrl+Shift+F9 в контексте отладки): вычислите выражение Объект.Метаданные().Реквизиты.Найти("ИмяРеквизита") и посмотрите, что оно возвращает. Это быстрее, чем добавлять временные сообщения в код.

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

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

Проверка существующего реквизита
Норма

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

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

Возвращается Неопределено — проверьте имя и коллекцию (стандартные или обычные)

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

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

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

Возникает ошибка — значит, ошибка раньше, при получении метаданных

Обращение к значению после проверки
Норма

Значение читается без исключения

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

Ошибка «Поле объекта не обнаружено» — проверка написана неверно или пропущена

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

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

У ссылки доступны только стандартные реквизиты. Чтобы проверить состав реквизитов, получите метаданные через ссылку: Ссылка.Метаданные().Реквизиты.Найти(Имя). Само значение реквизита при этом придётся получать запросом или через Ссылка.ПолучитьОбъект().

Как проверить наличие реквизита у всех документов конфигурации сразу?

Обойдите циклом коллекцию Метаданные.Документы и для каждого элемента вызовите Реквизиты.Найти(ИмяРеквизита). Так можно, например, найти все документы, у которых есть реквизит «Организация» или «Комментарий».

Почему Реквизиты.Найти() не находит поле «Ссылка» или «Дата»?

Это стандартные реквизиты, они хранятся в отдельной коллекции СтандартныеРеквизиты объекта метаданных. Проверяйте их там либо обрабатывайте как известный фиксированный набор.

Можно ли проверить наличие поля в запросе, не обращаясь к метаданным?

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

Работает ли проверка через метаданные для объектов из расширения конфигурации?

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

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

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

Итог

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

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