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

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

Как проверить существование поля в 1С

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

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

В 1С:Предприятии 8 есть несколько подходов к такой проверке: анализ метаданных, метод НайтиПоИмени для табличных частей и строк соединения, попытка обращения через Попытку/Исключение, а также проверка через запрос с конструкцией ВЫБОР КОГДА. Каждый способ имеет свою область применения, скорость и ограничения.

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

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

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

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

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

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

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

// Использование

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

НомерВх = ДокументОбъект.НомерВходящегоДокумента;

Иначе

НомерВх = "";

КонецЕсли;

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

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

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

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

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

КонецЕсли;

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

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

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

КонецЕсли;

КонецЦикла;

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

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

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

Колонка табличной части документа

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

Функция ЕстьКолонкаТЧ(МетаданныеОбъекта, ИмяТЧ, ИмяКолонки)

МетаТЧ = МетаданныеОбъекта.ТабличныеЧасти.Найти(ИмяТЧ);

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

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

КонецЕсли;

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

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

Ключ в структуре или соответствии

Если данные хранятся в структуре (например, результат разбора JSON или параметры обработки), используется метод Свойство. Он заполняет переданную переменную и возвращает Истина, если ключ найден.

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

Если СтруктураДанных.Свойство("Артикул", ЗначениеПоля) Тогда

// поле есть, ЗначениеПоля заполнено

Иначе

// поля нет — выполняем обходной сценарий

КонецЕсли;

У соответствия вместо Свойство применяется метод Получить(Ключ): он возвращает Неопределено, если ключа нет. Учтите тонкость: если значение по существующему ключу само равно Неопределено, отличить «ключа нет» от «значение пустое» таким способом нельзя.

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

Обращение к полю внутри конструкции Попытка/Исключение — рабочий, но грубый приём. Если поле отсутствует, платформа выбрасывает исключение, которое перехватывается, и код продолжает выполнение.

Попытка

Значение = Объект.ВозможноеПоле;

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

Исключение

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

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

Такой подход оправдан, когда тип объекта заранее неизвестен и метаданные получить нельзя — например, при работе с произвольными COM-объектами, строками соединения или результатами внешних компонент. Для штатных объектов 1С предпочтительнее проверка через метаданные: она быстрее и не маскирует другие ошибки.

Проверка поля в запросе и в СКД

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

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

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

ТекстПоля = "Док.ЗаказКлиента КАК Заказ";

Иначе

ТекстПоля = "НЕОПРЕДЕЛЕНО КАК Заказ";

КонецЕсли;

ТекстЗапроса = "ВЫБРАТЬ " + ТекстПоля + " ИЗ Документ.РеализацияТоваровУслуг КАК Док";

В схеме компоновки данных проверка поля набора данных выполняется через коллекцию Поля соответствующего набора: СхемаКомпоновкиДанных.НаборыДанных.НаборДанныхЗапрос.Поля.Найти("ИмяПоля"). Это полезно в отчётах, где состав полей зависит от функциональных опций.

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

Проверка поля у строки соединения и внешних источников

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

Для строк таблицы значений проверка колонки делается через коллекцию Колонки: ТаблицаЗначений.Колонки.Найти("ИмяКолонки"). Метод вернёт объект колонки или Неопределено. Это стандартный приём при загрузке данных из файлов, где состав колонок может меняться.

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

Типичные ошибки и ограничения

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

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

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

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

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

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

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

Вызов функции с существующим реквизитом
Норма

Возвращается Истина, значение поля читается без ошибок

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

Возвращается Ложь — проверьте регистр имени и коллекцию (Реквизиты или СтандартныеРеквизиты)

Вызов с несуществующим именем
Норма

Возвращается Ложь, выполняется обходной сценарий

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

Возникает исключение — значит, проверка выполняется после обращения к полю, а не до

Работа в клиент-серверном режиме
Норма

Проверка выполняется в серверной процедуре

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

Лишние серверные вызовы в цикле на клиенте — вынесите проверку из цикла

Итог

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

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

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

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

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

Дата, Номер, Проведен и подобные поля — стандартные реквизиты. Они хранятся в коллекции СтандартныеРеквизиты, а не в Реквизиты. Переберите её в цикле и сравните свойство Имя каждого элемента.

Можно ли проверить поле у произвольного значения неизвестного типа?

Сначала определите тип через ТипЗнч() и Тип(). Если значение ссылочное — используйте метаданные, если структура — метод Свойство(). Для остальных случаев остаётся Попытка/Исключение с обязательным анализом ОписаниеОшибки().

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

Используйте ТаблицаЗначений.Колонки.Найти("ИмяКолонки"). Если метод вернул Неопределено — колонки нет, и обращение к ней в строках таблицы вызовет ошибку. Это стандартная защита при загрузке данных из Excel или CSV с переменным составом колонок.

Влияет ли регистр имени реквизита на результат поиска?

Внутри одной базы метод Найти по метаданным обычно нечувствителен к регистру, но при работе через COM-соединение поведение может отличаться. Надёжнее перебрать коллекцию циклом и сравнивать ВРег(Реквизит.Имя) = ВРег(ИскомоеИмя).

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

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