Анализ использования метаданных в расширениях

29.12.21

Разработка - Механизмы платформы 1С

Готовый шаблон кода для быстрого анализа использования метаданных в расширениях.

Добрый день, коллеги.

Так уж случилось, что в наследство досталась конфигурация, в которой подрядчик наклепал 36 своих расширений. Разработка подрядчиком велась долго, программисты менялись, архитектора на проекте не было. Как следствие продукт на выходе получился с очень большой головной болью в виде расширений, причем новые реквизиты объекта метаданных добавлялись как в основную конфигурацию так и 1-2 и более расширений.

Естественно, на продакте начались серьезные проблемы как с производительностью, так и частые падения кеша  + масса багов при компиляции модулей. В итоге бороться с этим кошмаром можно только переписав все расширения в основную конфигурацию, перегрузив данные из таблиц расширений ит.д. 

Основная проблема это проанализировать все расширения на предмет метаданных, их использования, определить, где и какой объект метаданных принадлежит основной конфигурации, а где добавлен через расширение.

Немного покопавшись в теории, информации на форуме родился простой код, который позволяет это сделать быстро и безболезненно. Код в этой статье представлен в качестве примера и носит показательный характер. При этом он вполне рабочий.
Цель статьи - предоставить коллегам, столкнувшимся с подобным мракобесием, готовый шаблон кода, выдающий таблицу значений с анализом. Возможно, кому-то пригодится.

Пример кода анализа всех расширений по метаданным на примере "Документов":
 

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

 

Метаданных в расширениях шаблон кода

См. также

Сервисы интеграции без Шины и интеграции

Механизмы платформы 1С Программист Стажер Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Пример использования «Сервисов интеграции» без подключения к Шине и без обменов.

13.03.2024    3208    dsdred    16    

65

Как готовить и есть массивы

Механизмы платформы 1С Программист Стажер Платформа 1С v8.3 Бесплатно (free)

Все мы используем массивы в своем коде. Это один из первых объектов, который дают ученикам при прохождении обучения программированию. Но умеем ли мы ими пользоваться? В этой статье я хочу показать все методы массива, а также некоторые фишки в работе с массивами.

24.01.2024    7485    YA_418728146    25    

69

Планы обмена VS История данных

Перенос данных 1C Механизмы платформы 1С Системный администратор Программист Стажер Платформа 1С v8.3 Бесплатно (free)

Вы все еще регистрируете изменения только на Планах обмена и Регистрах сведений?

11.12.2023    7729    dsdred    36    

115

1С-ная магия

Механизмы платформы 1С Программист Бесплатно (free)

Язык программирования 1С содержит много нюансов и особенностей, которые могут приводить к неожиданным для разработчика результатам. Сталкиваясь с ними, программист начинает лучше понимать логику платформы, а значит, быстрее выявлять ошибки и видеть потенциальные узкие места своего кода там, где позже можно было бы ещё долго медитировать с отладчиком в поисках источника проблемы. Мы рассмотрим разные примеры поведения кода 1С. Разберём результаты выполнения и ответим на вопросы «Почему?», «Как же так?» и «Зачем нам это знать?». 

06.10.2023    20093    SeiOkami    46    

124

Дефрагментация и реиндексация после перехода на платформу 8.3.22

Механизмы платформы 1С Системный администратор Платформа 1С v8.3 Бесплатно (free)

Начиная с версии платформы 8.3.22 1С снимает стандартные блокировки БД на уровне страниц. Делаем рабочий скрипт, как раньше.

14.09.2023    14025    human_new    27    

77

Валидация JSON через XDTO (включая массивы)

WEB-интеграция Универсальные функции Механизмы платформы 1С Программист Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

При работе с интеграциями рано или поздно придется столкнуться с получением JSON файлов. И, конечно же, жизнь заставит проверять файлы перед тем, как записывать данные в БД.

28.08.2023    10384    YA_418728146    7    

148

Внешние компоненты Native API на языке Rust - Просто!

Механизмы платформы 1С Программист Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Внешние компоненты для 1С можно разработывать очень просто, пользуясь всеми преимуществами языка Rust - от безопасности и кроссплатформенности до удобного менеджера библиотек.

20.08.2023    7004    sebekerga    54    

99
Отзывы
6. Yashazz 4743 03.01.22 15:27 Сейчас в теме
Остальные комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. ITSun 29.12.21 09:50 Сейчас в теме
По моему скромному мнению, было бы хорошо прикрепить к статье какую-либо наглядную визуализацию анализа помимо таблицы.
2. Восьмой 88 29.12.21 10:43 Сейчас в теме
(1) В ближайшее время выложу полноценную обработку, а сейчас это именно шаблон кода.
3. Evg-Lylyk 4664 29.12.21 10:55 Сейчас в теме
Здоровы бы было занести добавление строки в процедуру
https://paste1c.ru/4llz4lvtsi7f
стало бы короче и понятней
4. Восьмой 88 29.12.21 11:46 Сейчас в теме
(3) Коллеги всему свое время, сейчас это шаблон кода, макет так сказать - ядра будущей обработки.
5. tigcorp 3 29.12.21 20:19 Сейчас в теме
В качестве затеи под дальнейшую разработку. Можно еще обходить ЭлементМетаданныхРасширения.Формы
6. Yashazz 4743 03.01.22 15:27 Сейчас в теме
7. Vasvas05 24 28.01.24 23:52 Сейчас в теме
//----------
			ОсновнойОбъектМетаданных = Метаданные.НайтиПоПолномуИмени(СтрокаТаблицыМетаданных.ПолноеИмяМетаданных);
			Если ОсновнойОбъектМетаданных = Неопределено Тогда
				СтрокаТаблицыМетаданных.ОбъектДобавленЧерезРасширение = Истина;
			Иначе
				СтрокаТаблицыМетаданных.ОбъектДобавленЧерезРасширение = (ОсновнойОбъектМетаданных.РасширениеКонфигурации();
			КонецЕсли;
Показать

правильно будет
//----------
			ОсновнойОбъектМетаданных = Метаданные.НайтиПоПолномуИмени(СтрокаТаблицыМетаданных.ПолноеИмяМетаданных);
			Если ОсновнойОбъектМетаданных = Неопределено Тогда
				СтрокаТаблицыМетаданных.ОбъектДобавленЧерезРасширение = Истина;
			Иначе
				СтрокаТаблицыМетаданных.ОбъектДобавленЧерезРасширение = (ОсновнойОбъектМетаданных.РасширениеКонфигурации()<>Неопределено);
			КонецЕсли;
			//----------
Показать
Восьмой; +1 Ответить
8. cdiamond 235 01.02.24 09:19 Сейчас в теме
Естественно, на продакте начались серьезные проблемы как с производительностью, так и частые падения кеша + масса багов при компиляции модулей.


Какие ваши доказательства? Ничего подобного не наблюдается на клиентских ERP где > 50 расширений с дополнением хранимых данных. На производительность это даже теоретически влиять не может, т.к. расширение создает новую таблицу СУБД заместо таблицы основной конфигурации (очищая его).
Во Фреше это вообще единственный метод доработки и добавления регистров. Не нужно вводить в заблуждение начинающих архитекторов о вредности большого количества расширений. Если они функционально разделены то это упрощает сопровождение.
Единственная проблема расширений с добавленными регистрами и реквизитами - это то что данные в расширениях иногда могут помешать обновлению, встречались ошибки реструктуризации, лечилось только полным удалением расширения. Но тогда встает задача выгрузить все данные расширений в файл и после обновления вернуть все назад на место.
9. Восьмой 88 03.02.24 19:19 Сейчас в теме
(8) Коллега Вам делать нечего как поднимать тему 21 года?
Мои доказательства плохо сделанная работа от франчей где в 10 расширениях по разному ломали один и тот-же объект как с изменением кода так и с модификацией таблиц данных на технологиях того времени.
Статья как раз была посвящена тому как бездумное и без системное клепания кучи расширений без архитекторского надзора приводит к серьезным последствиям.
Оставьте свое сообщение