При разработке универсальных механизмов в системе 1С:Предприятие, таких как правила обмена данными или алгоритмы обработки документов, часто возникает задача: проверить, есть ли в конкретном документе реквизит определенного типа (например, «Организация»). Начинающие разработчики часто пытаются использовать метод Содержит() коллекции метаданных, ожидая, что система сопоставит объект конфигурации с реквизитом. Однако такой подход возвращает Ложь. В этой статье мы подробно разберем, почему так происходит, и изучим правильные методы проверки метаданных.
Рассмотрим типичную ситуацию. Программист пишет код, который должен определить, относится ли документ к конкретной организации:
МетаданныеДока = Метаданные.Документы.РеализацияТоваровУслуг;
Если МетаданныеДока.Реквизиты.Содержит(Метаданные.Справочники.Организации) Тогда
// Этот код никогда не выполнится
КонецЕсли;
Давайте проанализируем ситуацию и выясним причину такого поведения системы. Коллекция МетаданныеДока.Реквизиты содержит объекты типа ОбъектМетаданных: Реквизит. В то же время Метаданные.Справочники.Организации — это объект типа ОбъектМетаданных: Справочник.
Метод Содержит(Элемент) проверяет физическое наличие конкретного экземпляра объекта в коллекции. Поскольку объект метаданных «Справочник» в принципе не может являться «Реквизитом» (это разные сущности метаданных), проверка всегда будет отрицательной. Мы пытаемся найти «яблоко» в корзине с «апельсинами», даже если эти фрукты одного цвета.
Если наша задача — просто убедиться, что у документа существует реквизит с именем «Организация», самым безопасным и правильным способом будет использование метода Найти(). В отличие от прямого обращения через точку (например, МетаданныеДока.Реквизиты.Организация), метод Найти() не вызывает критическую ошибку, если поле отсутствует.
Рассмотрим правильный алгоритм поиска:
ИмяНужногоРеквизита = "Организация";
РеквизитМетаданных = МетаданныеДока.Реквизиты.Найти(ИмяНужногоРеквизита);
Если РеквизитМетаданных <> Неопределено Тогда
Сообщить("Реквизит найден!");
Иначе
Сообщить("У данного документа нет собственного реквизита с таким именем.");
КонецЕсли;
Этот метод возвращает объект метаданных реквизита, если он существует, или Неопределено, если его нет. Это позволяет писать чистый код без использования громоздких конструкций Попытка...Исключение.
Часто нам недостаточно знать, что реквизит существует. Нам нужно убедиться, что этот реквизит имеет тип «СправочникСсылка.Организации». Для этого мы должны проанализировать свойство Тип найденного реквизита.
Давайте разберем по шагам, как проверить вхождение конкретного типа в описание типов реквизита:
Тип, которое имеет тип ОписаниеТипов.СодержитТип() для проверки соответствия.Пример реализации:
РеквизитМетаданных = МетаданныеДока.Реквизиты.Найти("Организация");
Если РеквизитМетаданных <> Неопределено Тогда
ТипОрганизации = Тип("СправочникСсылка.Организации");
Если РеквизитМетаданных.Тип.СодержитТип(ТипОрганизации) Тогда
Сообщить("Реквизит имеет нужный нам тип.");
КонецЕсли;
КонецЕсли;
Если вы работаете в современной конфигурации, построенной на базе Библиотеки стандартных подсистем (БСП), вам не нужно изобретать велосипед. Программисты 1С уже подготовили удобные программные интерфейсы, которые учитывают множество нюансов.
Рекомендуется использовать функцию ОбщегоНазначения.ЕстьРеквизитОбъекта(). Рассмотрим ее преимущества:
Пример использования БСП:
ИмяРеквизита = "Организация";
Если ОбщегоНазначения.ЕстьРеквизитОбъекта(ИмяРеквизита, Метаданные.Документы.РеализацияТоваровУслуг) Тогда
// Логика обработки
КонецЕсли;
Проанализируем ситуацию, которая часто ставит в тупик даже опытных разработчиков. Вы визуально видите поле «Организация» в форме документа, но метод МетаданныеДока.Реквизиты.Найти("Организация") возвращает Неопределено.
Причина: Реквизит может быть Общим реквизитом. В архитектуре 1С общие реквизиты вынесены в отдельную ветку метаданных и не отображаются в коллекции Реквизиты конкретного документа.
Чтобы проверить, участвует ли наш документ в общем реквизите, необходимо выполнить следующие действия:
ОбщийРеквизит = Метаданные.ОбщиеРеквизиты.Организация;
Если ОбщийРеквизит.Состав.Найти(МетаданныеДока) <> Неопределено Тогда
Если ОбщийРеквизит.Состав[МетаданныеДока].Использование = Метаданные.ВариантИспользованияОбщегоРеквизита.Использовать Тогда
Сообщить("Организация доступна через общий реквизит.");
КонецЕсли;
КонецЕсли;
Если вы выполняете проверку метаданных внутри цикла (например, при массовой выгрузке данных в КД 2.0 или обработке сотен тысяч записей регистра сведений), постоянное обращение к дереву метаданных может замедлить работу.
В таких случаях мы рекомендуем использовать кэширование. Перед началом цикла соберите список имен всех реквизитов документа в структуру или таблицу значений. Поиск ключа в структуре выполняется значительно быстрее, чем многократный поиск в коллекции метаданных через точку.
Подведем итог: для проверки наличия реквизита используйте метод Найти() или функции БСП. Для проверки типа — метод СодержитТип() у описания типов. И никогда не забывайте проверять коллекцию общих реквизитов, если поле не найдено в локальных реквизитах объекта.