31 янв. 2016 г.

Просмотр структуры базы данных

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




Код обработки:

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
 
 ОбновитьТаблицы();
 
КонецПроцедуры

&НаСервере
Процедура ОбновитьТаблицы()
 
 мТаблицыХранения = ПолучитьСтруктуруХраненияБазыДанных(, Истина);
 ИндексыСтрок = Новый Соответствие;
 МетаданныеКорень = СтруктураИБ.ПолучитьЭлементы().Добавить();
 МетаданныеКорень.Объект = "Метаданные";
 КореньИД = МетаданныеКорень.ПолучитьИдентификатор();
 ИндексыСтрок.Вставить("Метаданные", КореньИД);
 Для Каждого СтрокаХранения Из мТаблицыХранения Цикл
  ДобавитьМетаданныеОбъекта(ИндексыСтрок, СтрокаХранения);
 КонецЦикла;
 
КонецПроцедуры

&НаСервере
Процедура ДобавитьМетаданныеОбъекта(ИндексыСтрок, СтрокаХранения)

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

КонецПроцедуры // ДобавитьМетаданныеОбъекта()

&НаКлиенте
Процедура СтруктураИБПриАктивизацииСтроки(Элемент)
 
 ОбновитьСвязанныеПоля();
 
КонецПроцедуры

&НаКлиенте
Процедура ОбновитьСвязанныеПоля()

 ПоляКоличество = 0;
 ИндексыКоличество = 0;
 ТекущиеДанные = Элементы.СтруктураИБ.ТекущиеДанные;
 ОбновитьСвязанныеПоляКлиент(ТекущиеДанные.Адрес);

КонецПроцедуры // ОбновитьСвязанныеПоля()

&НаКлиенте
Процедура ОбновитьСвязанныеПоляКлиент(АдресПолей)

 ДеревоИндексов.ПолучитьЭлементы().Очистить();
 ПоляОбъекта.Очистить();
 Если ЗначениеЗаполнено(АдресПолей) Тогда
  СтруктураЗаполнения = ПолучитьСтруктуруЗаполнения(АдресПолей);
  ЗаполнитьПоляКлиент(СтруктураЗаполнения.Поля);
  ЗаполнитьИндексыКлиент(СтруктураЗаполнения.Индексы);
 КонецЕсли;

КонецПроцедуры // ОбновитьСвязанныеПоляКлиент()

&НаКлиенте
Процедура ЗаполнитьПоляКлиент(ДанныеПолей)

 Для Каждого СтрокаДанных Из ДанныеПолей Цикл
  ЗаполнитьЗначенияСвойств(ПоляОбъекта.Добавить(), СтрокаДанных);
 КонецЦикла;
 ПоляКоличество = ПоляОбъекта.Количество();

КонецПроцедуры // ЗаполнитьПоляКлиент()

&НаКлиенте
Процедура ЗаполнитьИндексыКлиент(ДанныеИндексов)

 ЭлементыДерева = ДеревоИндексов.ПолучитьЭлементы();
 Для Каждого ДанныеИндекса Из ДанныеИндексов Цикл
  ЭлементИндекс = ЭлементыДерева.Добавить();
  ЭлементИндекс.ИмяПоляХранения = ДанныеИндекса.ИмяПоляХранения;
  ПоляИндекса = ЭлементИндекс.ПолучитьЭлементы();
  Для Каждого СтрокаДанных Из ДанныеИндекса.СоставИндекса Цикл
   ЗаполнитьЗначенияСвойств(ПоляИндекса.Добавить(), СтрокаДанных);
  КонецЦикла;
  Элементы.ДеревоИндексов.Развернуть(ЭлементИндекс.ПолучитьИдентификатор());
 КонецЦикла;
 ИндексыКоличество = ЭлементыДерева.Количество();

КонецПроцедуры // ЗаполнитьПоляКлиент()

&НаСервереБезКонтекста
Функция ПолучитьСтруктуруЗаполнения(ИдентификаторСтруктуры)

 СтруктураЗаполнения = Новый Структура("Поля, Индексы", Новый Массив, Новый Массив);
 ТаблицыСтроки = ПолучитьИзВременногоХранилища(ИдентификаторСтруктуры);
 Если НЕ ТаблицыСтроки = Неопределено Тогда
  ЗаполнитьПоля(СтруктураЗаполнения.Поля, ТаблицыСтроки.Поля);
  ЗаполнитьИндексы(СтруктураЗаполнения.Индексы, ТаблицыСтроки.Индексы);
 КонецЕсли;
 
 Возврат СтруктураЗаполнения;

КонецФункции // ПолучитьСтруктуруЗаполнения()

&НаСервереБезКонтекста
Процедура ЗаполнитьПоля(ХранилищеПолей, ДанныеПолей)

 Для Каждого СтрокаДанных Из ДанныеПолей Цикл
  ХранилищеПолей.Добавить(ЗаполнитьСоставСтроки(СтрокаДанных));
 КонецЦикла;

КонецПроцедуры // ЗаполнитьПоля()

&НаСервереБезКонтекста
Процедура ЗаполнитьИндексы(ХранилищеПолей, ДанныеИндексов)

 Для Каждого ИндексОбъекта Из ДанныеИндексов Цикл
  СоставИндекса = Новый Массив;
  СтруктураИндекса = Новый Структура("ИмяПоляХранения, СоставИндекса", ИндексОбъекта.ИмяИндексаХранения, СоставИндекса);
  Для Каждого ПолеИндекса Из ИндексОбъекта.Поля Цикл
   СоставИндекса.Добавить(ЗаполнитьСоставСтроки(ПолеИндекса));
  КонецЦикла;
  ХранилищеПолей.Добавить(СтруктураИндекса);
 КонецЦикла;

КонецПроцедуры // ЗаполнитьИндексы()

&НаСервереБезКонтекста
Функция ЗаполнитьСоставСтроки(ДанныеСтруктуры)

 СтрокаСтруктуры = Новый Структура("ИмяПоляХранения, ИмяПоля, Метаданные");
 ЗаполнитьЗначенияСвойств(СтрокаСтруктуры, ДанныеСтруктуры);
 Возврат СтрокаСтруктуры;

КонецФункции // ЗаполнитьСоставСтроки()

СтруктураИБ_УФ.epf

5 комментариев:

  1. Спасибо, классная вещь!

    ОтветитьУдалить
  2. Спасибо! А содержимое самих таблиц нельзя просматривать (на чтение, конечно)?

    ОтветитьУдалить
    Ответы
    1. Метод ПолучитьСтруктуруХраненияБазыДанных возвращает только таблицу значений с описаниями структуры таблиц на стороне СУБД, без данных. При необходимости можете сделать доработку получения данных по имени таблицы, например через COM.

      Удалить