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