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