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