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