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