Групповое редактирование метаданных

Потребность в групповом редактировании довольно часто обсуждалось и обсуждается в среде специалистов, плотно работающих с большими конфигурациями. Некоторые концептуальные изменения вносимые в конфигурации требуют наличия определенных реквизитов в объектах метаданных. Обойти это можно конечно с помощью плана видов характеристик, ну у здесь полно подводных камней. Представленное здесь решение позволяет работать с любым составом объектов метаданных ( добавлять,изменять,удалять и копировать). Решение тестировалось на платформе 8.1.7. в клиент серверной версии. Реализация представленной здесь концепции возможно и на платформе 8.0, однако в виду того что в 8.1 были пересмотрены некоторые принципы хранения описания метаданных, было выбрана реализация именно на 8.1.
Enterprise Integrator/

Потребность в групповом редактировании довольно часто обсуждалось и обсуждается в среде специалистов, плотно работающих с большими конфигурациями. Некоторые концептуальные изменения вносимые в конфигурации требуют наличия определенных реквизитов в объектах метаданных. Обойти это можно конечно с помощью плана видов характеристик, ну у здесь полно подводных камней. Представленное здесь решение позволяет работать с любым составом объектов метаданных ( добавлять,изменять,удалять и копировать). Решение тестировалось на платформе 8.1.7. в клиент серверной версии. Реализация представленной здесь концепции возможно и на платформе 8.0, однако в виду того что в 8.1 были пересмотрены некоторые принципы хранения описания метаданных, было выбрана реализация именно на 8.1.

Итак начнем

Вначале краткий ликбез по тому как храняться описания метаданных. Все описания метаданных базы данных хранятся в таблице Config, изменения внесенные в конфигурацию конфигуратором (изменения можно вносить также с помощью Enterprise Integrator) сохраняются в таблице ConfigSave. После обновления конфигурации записи из таблицы ConfigSave заменяют записи из таблицы Config.

Структура обоих этих таблиц одинакова. В качестве ключа представлено поле FileName в этом поле храниться уникальный идентификатор объекта метаданных ( в данном случае это это может быть как какой-то прикладной объект, так и некоторые свойства этого объекта, такие как Макеты и Формы).

Нас в данном случае будут интересовать записи таблицы Config, в которых описаны реквизиты, табличные части и прочие свойства метаданных. В форме объектов конфигурации данные записи будут иметь имя «Метаданные» и будут подчинены непосредственно объекту конфигурации (описание метаданные существуют также для форм но кроме названия и версий форм они содержат мало интересного).

В версии 8.0 все записи с именем «Метаданные»(описание метаданных), всех!! объектов метаданных были объединены в одну (metadata)-эта запись была самой большой в конфигурации, что и затрудняло ее редактирование.

Цели

Для изменения метаданных объекта конфигурации достаточно:

  • отредактировать запись описания метаданных;

  • изменить версию объекта конфигурации и всей конфигурации(используется запись Versions);

Посмотрим, что же содержит в себе запись описания метаданных.

Структура запись похожа на Xml файл где вместо разделителей <> разделители {} Элементы, содержавшие набор однотипных объектов содержат флаговый идентификатор(45е46cbc-3…… или любой другой), после которого перечислено количество объектов в элементе (22).

На рисунке изображен один из 22, элемент набора записей, который характеризует реквизиты объектов метаданных. Этот блок текста представляет собой внутренне значение реквизита метаданных. (Жаль что объекты метаданных не сериализуются, в противном случае вероятно данный блок текста можно было бы, получить используя следующую конструкцию ЗначениеВСтрокуВнутр(Метаданные.Документы.АВСКлассификация.Реквизиты.Комментарий)) . Изменяя состав элементов содержащихся в блоке, мы меняем состав реквизитов метаданных или их свойства в том случае если меняем значения элементов блока.

Общий подход

Поле того, как мы определились с целями, поговорим о текущей реализации.

Не так сложно получить (прочитать внутреннее значение элементов метаданных) как их отредактировать с учетом требований.Enterprise Integrator предлагает следующее универсальное решение.

Внутреннее представление можно представить в виде структуры значений, содержащие списки значений. В списки значений помещаются однотипные объекты элементов, во главе которых стоит флаговый идентификатор, по этому флаговому идентификатору и определяются, какое свойство объектов метаданных перечислено в списке (таблица соответствий, Флаговый идентификатор-Свойство находится Настройка - Объекты конфигурации - Обозреватель объектов). Список значений, свойств объектов метаданных, формируется таким образом, чтобы при его обратном представлении в строковое представление, было получено такое же строковое значение элемента, как и до преобразования.

В рамках этой стратегии для изменения реквизитов объектов метаданных нужно выполнить следующий алгоритм.

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

Структура свойства

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



На рисунке представлен реквизит документа. Почти все свойства метаданных (реквизиты) разных типов прикладных объектов различны и следовательно внутренне представление этих свойств за исключением некоторых полей (UNID,Имя, Синоним, Комментарий[,Тип]) различны. Постоянной структурой любого реквизита объекта метаданных являются не затененные элементы, структура затененных элементов может меняться в зависимости от:

  • типа прикладного объекта;
  • значения свойства;
  • в рамках одного элемента от значения дополнительных свойство объекта метаданных в целом, например для справочника (иерархический, не иерархический), для регистра сведений (подчинен или не подчинен регистратору) и т.п.

Таким образом, мы выяснили, что относительно начала списка значений (начала строки) все элементы одинаковы. Однако как хорошо, что все в этом мире относительно и к своей радости мы замечаем, что относительно Unid все элементы свойств метаданных (реквизитов) до какой то границы (как вверх, так и вниз) одинаковы. Для того, что предоставить пользователю, более-менее приемлемые методы изменения значений элемента свойства метаданных. Создана структура, в которую помешены элементы списков значений.

Имя

Значение(для первых 2 рисунков)

Unid

СписокЗначений[0],Значение[0].Значение[1].Значение[1].Значение[2]

Имя

СписокЗначений[0],Значение[0].Значение[1].Значение[2]

Синоним

СписокЗначений[0],Значение[0].Значение[1].Значение[3] .Значение[2]

Комментарий

СписокЗначений[0],Значение[0].Значение[1].Значение[4]

Тип

СписокЗначений[0],Значение[0].Значение[2]

Причем расчет адресов элементов структуры происходить относительно уникального идентификатора, то есть вначале рассчитывается адрес Unid (0,0,1,1,2) после чего для остальных элементов рассчитывается отклонение от адреса Unid, (как я уже упоминал) «теория относительности» нам немного помогла.

Объекты=ПолучитьОбъектыМетаданных(Элемент.Значение.ПолучитьТекст());

Если Объекты.Свойство("Реквизиты") Тогда

НовыйСоставОбъектов=Объекты.Реквизиты.Скопировать();

Для каждого Свойство из НовыйСоставОбъектов Цикл

МД=ОбъектМетаданных(Свойство.Значение);

МД.UNID.Значение=Новый УникальныйИдентификатор;

МД.Комментарий.Значение=МД.Комментарий.Значение+" Ei;";

КонецЦикла;

КонецЕсли;

Выше приведенный код изменяет для всех элементов свойства (в данном случае «реквизиты») объекта метаданных, уникальный идентификатор и добавляет к комментариям определенную строку. В данном коде следует обратить внимание на то, что обращение к свойствам объекта метаданных для чтения или записи, происходит следующим образом:

ОбъектМетаданных(<Элемент коллекции (Реквизит)>).[Ключ].Значение=;

МД.UNID.Значение=

потому что в структуре хранится элемент списка значений.

Копирование элементов

Ну теперь мы вплотную подошли к самому сложному.

Попробуем перефразировать крылатую фразу.

«Для того что бы что-то куда-то вставить нужно что то и где-то скопировать?»

Вот для того, что бы определить это «что- то» и «где-то» нужно определится с источником. Источником может быть любой объект конфигурации с необходимым набором параметров, то есть источником для вставки элемента в реквизиты документа, справочника,… и т.д. может являться любое измерение или ресурс, возможно и обратное, однако измерение содержит больше свойств чем например реквизит (Ведущее, Запрет незаполненных значений), поэтому при добавлении эти свойства примут такое же значение, как и первый элемент коллекции, в которую добавляется новый элемент. Отличатся эти элементы (первый элемент коллекции и добавляемый элемент) будут только элементами постоянной структуры объектов метаданных (см. выше не затененные элементы).

На рисунке изображен результат копирования реквизита табличной части документа в измерения регистра сведений.

Однако для большей надежности рекомендуется копировать реквизиты одного типа. Это увеличит скорость копирования реквизитов и компенсирует возможные коллизии.

Для того что бы определить те реквизиты которые будем копировать необходимо в форме «Объекты конфигурации» выбрать в дереве объектов источник (прикладной объект содержащий нужные реквизиты). Для каждого прикладного объекта существуют в таблице Config запись без окончания (см. Формат уникального идентификатора) в этих записях, как уже было сказано выше, и хранится описание свойств метаданных прикладного объекта. После открытия этой записи в форме «Встроенного языка», в правой части этой формы будет сформирован обозреватель объекта – дерево значений, сформированное на основе внутреннего представления свойств метаданных, строится на основании флаговых идентификаторов перечисленных в настройках Параметры – Объекты конфигурации – Обозреватель объектов, колонки этого дерева содержат все доступные свойства элемента коллекции (пока это Unid,Имя, Синоним, Комментарий и Тип). Именно в обозревателе объектов нужно выбрать необходимые элементы свойств и передать их в форму "Конструктор запросов" для групповой обработки, выбрав пункт контекстного меню в обозревателе объекта.

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

Как уже упоминалось в самом начале, нас интересует только метаданные прикладных объектов, поэтому отметим только эти строчки в результатах запроса, для нужных (редактируемых) объектов. Это достаточно просто сделать еще количество редактируемы реквизитов не велико… Но мы затеяли всю эту «кашу» не для того чтобы «тупо» сидеть и выбирать 200 элементов например справочников в дереве значений. Поскольку редактировать тексты модулей или формы в нашу задачу сейчас не входит то по большей части нам необходимы только внутренние идентификаторы определенных прикладных объектов. Получить соответствие ПолноеИмя -Unid можно используя шаблон «Метаданные» Действия – Шаблоны –Метаданные (перебор) в форме «Конструктор запроса» . Данный шаблон представляет из себя следующее выражение на встроенном языке:

Результат=Новый ТаблицаЗначений;

Результат.Колонки.Добавить("Имя");

Результат.Колонки.Добавить("FileName");

Для каждого Объект из Справочники.ТипВсеСсылки().Типы() Цикл

//Для каждого Объект из Параметры.ТипыМД.Типы() Цикл //выбранные типы

//Для Каждого Объект ИЗ Метаданные.Обработки Цикл //не ссылочные типы

Мета=Неопределено;

Мета=?(ТипЗнч(Объект)=Тип("ОбъектМетаданных"),Объект,Метаданные.НайтиПоТипу(Объект));

Если Не Мета=Неопределено Тогда

НоваяСтрока=Результат.Добавить();

НоваяСтрока.Имя=Мета.ПолноеИмя();

НоваяСтрока.FileName=ПолучитьИдентификаторМД(Мета); // получаем идентификатор САМОЕ ГЛАВНОЕ

КонецЕсли;

КонецЦикла;

Результат.Сортировать("Имя Возр");

//ОбновитьВерсииИзменныхМетаданных(Параметры.ИзмененныеМД); //Регистрации версий для измененных метаданных, используется после групповой обработки

и позволяет определить внутренний уникальный идентификатор:

  • для всех объектов одного типа (Справочников или Документов или ….)-используя в заголовке цикла следующую конструкцию <МенеджерПрикладногоОбъекта>. ТипВсеСсылки().Типы();

  • для объектов различных типов нудные типы необходимо указать в параметре «ТипыМД» - используя в заголовке цикла следующую конструкцию Для каждого Объект из Параметры.ТипыМД.Типы() Цикл;

  • Для всех объектов не ссылочного типа (обработок, отчетов) по средствам перебора объектов метаданных

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

Имя

FileName

Справочник.АдресныеСокращения

51a76d2c-d813-44d9-9cfe-deaec665d0bf

Справочник.Банки

61c6b6e2-1f7c-4ed8-b11e-db2948741e5e

Справочник.БанковскиеСчета

7d0792c3-1038-4cb9-a661-0c0600581589

Справочник.БланкиСтрогойОтчетности

03cf27c8-12f8-49b0-894e-8e6513b34553

……

..

Справочник.ЯзыкиНародовМира

735a6318-4f04-45e2-8814-21afb95c87e1

Данная таблица будет содержать исходные данные «куда-то вставить» необходимые для обработки.

Теперь для любой колонки данной таблицы значений или дерева значений (если мы не использовали шаблон) применим групповую обработку «Произвольный алгоритм» со следующим выражением на встроенным языке.

СписокТекстов=ПолучитьСодержаниеМетаданных(ТекущиеДанные.FileName);

Для каждого Элемент из СписокТекстов Цикл

Если ТипЗнч(Элемент.Значение)=Тип("ТекстовыйДокумент")Тогда

Объекты=ПолучитьОбъектыМетаданных(Элемент.Значение.ПолучитьТекст());

Если Объекты.Свойство("Реквизиты") Тогда

//Добавляем объекты

Изменен=Ложь;

НовыйСоставОбъектов=Объекты.Реквизиты.Скопировать();

Для каждого НовыйОбъект из Параметры.СписокСвойств Цикл

МД=ОбъектМетаданных(НовыйОбъект.Значение);

ОбъектМД=Метаданные.НайтиПоПолномуИмени(ТекущиеДанные.Имя);

Если ОбъектМД.Реквизиты.Найти(МД.Имя.Значение)=Неопределено Тогда //проверяем нет ли реквизитов с таким же именем

Изменен=Истина;

МД.UNID.Значение=Новый УникальныйИдентификатор; //Установка нового уникального идентификатора обязательна

НовыйСоставОбъектов.Добавить(НовыйОбъект.Значение,НовыйОбъект.Представление,НовыйОбъект.Пометка);

КонецЕсли;

КонецЦикла;

Если Изменен Тогда

//Заменяем

ЗаменитьСписокОбъектаМетаданных(Объекты.Реквизиты,НовыйСоставОбъектов,Элемент.Значение);

Параметры.ИзмененныеМД.Добавить(ТекущиеДанные.FileName);

КонецЕсли;

КонецЕсли;

КонецЕсли;

КонецЦикла;

Если Изменен Тогда

СохранитьСодержаниеМетаданных(ТекущиеДанные.FileName,СписокТекстов,,Ложь);

КонецЕсли;

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

Процедура

Назначение

Параметры

Имя

Назначение

ПолучитьСодержаниеМетаданных

Получает содержание записи метаданных поскольку запись может состоять из двух блоков как например формы (модуль формы и сама форма) возвращаемым значением является список значений. В списке значений могут содержаться такие типы объектов как

  • Текстовый документ (модули, формы);

  • Табличный документ (таб. Макеты);

  • СКД;

  • Картинка;

  • HTML документ (Справка)

Unid

Уникальный идентификатор записи объекта в таблице

Таблица= «Config»

Таблица

«Config», «ConfigSave»

+ «Params»

ПолучитьОбъектыМетаданных

Формирует структуру аналогичную дереву в фрейме обозревателя объектов. Имена свойств структуры формируются на основе параметров для обозревателя объектов. В структуре значений содержатся списки значений, в которых перечислены свойства объектов метаданных

Текст

Системное представление всех свойств метаданных прикладного объекта

ОбъектМетаданных

Формирует структуру со значениями свойств элемента коллекции.

ЭлементКоллекции

Элемент списка значений определенного свойства прикладного объекта (Реквизит, ТЧ…)

ЗаменитьСписокОбъектаМетаданных

Заменяет в системном представлении метаданных прикладного объекта набор одних свойств на другой набор (измененный, дополненный) тех же самый свойств. Предварительно списки значений преобразовываются в строку.

ЗаменяемыйСЗ

Старый список значений с набором свойств прикладного объекта

НовыйСЗ

Новый список значений

Текст

Системное представление всех свойств метаданных прикладного объекта

СохранитьСодержаниеМетаданных

Сохраняет значения в файл упаковывает его и записывает в таблицу При необходимости выполняет обновлении версии измененного прикладного объекты (одного).

Unid

Уникальный идентификатор записи объекта в таблице

СписокЗначений

Измененный список

Таблица= «ConfigSave»

Таблица

«Config», «ConfigSave»

+ «Params». Запись сразу в таблицу Config при добавлении реквизитов не вызовут реструктуризацию БД

ОбновитьВерсии=Истина

При пакетной обработки лучше обновить все версии потом после выполнения увеличивает производительность

При копировании реквизитов необходимо проверять - не существуют ли реквизиты в прикладном объекте с одинаковыми именами. Именно для этого нам нужна колонка в «Имя»(Полное имя метаданных), по ней получается объект метаданных.

ОбъектМД=Метаданные.НайтиПоПолномуИмени(ТекущиеДанные.Имя);

Если ОбъектМД.Реквизиты.Найти(МД.Имя.Значение)=Неопределено Тогда //проверяем нет ли реквизитов с таким же именем

После выполнения групповой обработки записи, которые были изменены, в которых окажутся новые реквизиты, будут содержатся в таблице ConfigSave.

Этого в принципе достаточно для того что бы увидеть результат добавления реквизитов Конфигураторе (в том случае если конфигурация была уже открыта - ее необходимо перечитать). В том случае если внесенные изменения необходимо отменить, используйте форму «Объекты конфигурации» или другие доступные средства, для удаления записей из таблицы ConfigSave.

Для того, что бы конфигуратор смог корректно провести реструктуризацию информационной базы необходимо, чтобы для измененных объектов конфигурации были установлены новые идентификаторы версий. Идентификаторы версий для всех объектов метаданных описаны в файле Versions. Версии можно регистрировать при выполнении процедуры СохранитьСодержаниеМетаданных (см 4 параметр), однако куда выгоднее зарегистрировать все идентификаторы один раз. Именно для этого в произвольном алгоритме используется следующий код.

Параметры.ИзмененныеМД.Добавить(ТекущиеДанные.FileName);

То есть идентификаторы накапливаются в заранее установленном параметре (устанавливается параметр при передаче выбранных реквизитов из обозревателя объектов в форму «Конструктор запроса»). После выполнения групповой обработки идентификаторы можно зарегистрировать используя следующую процедуру.

ОбновитьВерсииИзменныхМетаданных(Параметры.ИзмененныеМД);

Данная процедура закомментирована в шаблоне Метаданные (перебор).

После регистрации версии в таблице ConfigSave появится еще 3 записи Config, ConfigSave, root. Теперь можно производить обновление информационной базы.

Разработчики Enterprise Integrator будут надеяться что данная технология найдет обширное применение в разработке конфигураций, и наконец уйдут в прошлое те времена когда конфигуратор был только «интерфейсным» объектом.

Начать дискуссию