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