В технологической платформе 8.3.11 был введен специальный механизм — «История данных». Этот механизм видится достаточно полезным, так как предоставляет ту функциональность, которую не редко приходится реализовывать вручную. В этой статье я попробую рассказать о том, что это за механизм, для чего он нужен и как с ним работать.
Общая информация
Начнем с общей теоретической информации о том, что такое история данных и как она устроена.
Описание и возможности
История данных — это механизм позволяющий хранить в базе данных упорядоченные по времени версии объектов конфигурации. Под версией понимаются данные, которые были в объекте на момент редактирования и состояние метаданных на момент редактирования. Хранить историю можно как для всего объекта целиком, так и для отдельных реквизитов — имеется возможность тонкой настройки работы механизма для каждого реквизита, в том числе табличные части.
Включать и выключать историю можно как из конфигуратора, так и средствами встроенного языка, все это дает возможность управлять историей для каждого пользователя отдельно.
Само по себе хранение истории достаточно бесполезная функция, поэтому с историей данных можно выполнять следующие операции:
- записывать версию данных;
- получать данные определенной версии;
- удалять данные определенной версии;
- получать разницу между двумя версиями одного объекта;
- прочие полезные возможности.
На момент написания статьи (8.3.13) история данных поддерживается для следующих объектов:
- общие реквизиты;
- константы;
- справочники;
- документы;
- бизнес-процессы;
- задачи;
- регистры сведений;
- планы обмена;
- планы счетов;
- планы видов характеристик;
- планы видов расчетов;
- расширения конфигурации.
Работа с историей данных регулируется правами доступа и отражается в журнале регистрации.
Устройство механизма
История данных хранится в специальных таблицах информационной базы. Кроме самих данных в этих таблицах хранятся метаданные прежних версий объектов. Версии метаданных создаются в момент изменения этих самых метаданных у объекта и никак не связаны с изменением данных объекта.
Также следует помнить, что на данный момент система не отличает включение версионирования для реквизита от создания реквизита и отключение версионирования реквизита от удаления реквизита.
Создание версии объекта состоит из двух этапов. Сначала, автоматически или с помощью специального метода, фиксируется факт изменения объекта и информация об этом изменении попадает в очередь. Перенос данных из очереди в таблицы базы выполняется методом ОбновитьИсторию(), этот метод можно выполнять асинхронно, например регламентным заданием. Идущие подряд изменения одного объекта не «склеиваются» и фиксируются отдельно, вне зависимости от периодичности обновления истории данных.
Настройка версирования объектов осуществляется либо из конфигуратора либо при помощи встроенного языка. Конфигуратор логично использовать в тех случаях, когда история данных потребуется во всех режимах работы приложения или на нее завязана какая-то прикладная логика. Использование встроенного языка потребуется для реализации более гибкой системы, например когда пользователя потребуется самому выбирать для каких объектов хранить историю данных.
Для управления историей данных объектов в конфигураторе реализовано свойство «История данных», оно присутствует как у основных объектов (у справочников, например) так и у подчиненных — реквизиты, табличные части с их реквизитами, ресурсы регистров сведений.
По умолчанию свойство «История данных» установлено в значение «Использовать» у:
- стандартных реквизитов;
- реквизитов объектов;
- реквизитов табличных частей;
- измерений регистров сведений (без возможности отключения);
- ресурсов регистров сведений.
Использование механизма
Для обращения к истории данных используется свойство глобального контекста ИсторияДанных, методы этого этого свойства будут рассмотрены ниже.
Управление использованием истории данных
Ниже приведены примеры того, как, средствами встроенного языка, можно управлять использованием истории данных. Отмечу, что значения свойства ИсторияДанных (полученные «через точку») берутся из конфигуратора и могут не соответствовать действительности, для получения актуальной информации нужно пользоваться методом ПолучитьНастройки().
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | &НаСервере Процедура УправлениеИспользованиемИсторииДанных() //Получения значения свойства "История данных" //установленного в конфигураторе у объекта ОбъектВключен = Метаданные.Справочники.Справочник1.ИсторияДанных; //у реквизита объекта РеквизитВключен = Метаданные.Справочники.Справочник1.Реквизиты.Найти("Реквизит1").ИсторияДанных; //у реквизита табличной части объекта РеквизитТЧВключен = Метаданные.Справочники.Справочник1.ТабличныеЧасти.ТабличнаяЧасть1.Реквизиты.Найти("Реквизит1").ИсторияДанных; //у стандартного реквизита объекта СтандартныйРеквизитВключен = Метаданные.Справочники.Справочник1.СтандартныеРеквизиты.Наименование.ИсторияДанных; //Получение информации об изменениях настроек истории данных Настройки = ИсторияДанных.ПолучитьНастройки(Метаданные.Справочники.Справочник1); //Изменение настройки истории данных средствами встроеннго языка Насторойки = Новый НастройкиИсторииДанных; //Настройка для самого объекта Насторойки.Использование = Истина; //Для реквизитов объекта Насторойки.ИспользованиеПолей.Вставить("Реквизит1", Ложь); Насторойки.ИспользованиеПолей.Вставить("ТабличнаяЧасть1.Реквизит1", Ложь); ИсторияДанных.УстановитьНастройки(Метаданные.Справочники.Справочник1, Насторойки); //Возвращаем настройки истории данных из конфигуратора ИсторияДанных.УстановитьНастройки(Метаданные.Справочники.Справочник1, Неопределено); КонецПроцедуры |
Запись версии
Обычно запись версии выполняется автоматически — в два этапа, как описано выше. Но иногда требуется перенести историю данных в системное хранилище из какого-либо другого хранилища. Для этого используется метод ЗаписатьВерсию() и в этом случае данные записываются сразу в таблицы информационной базы, без необходимости обновлять историю.
1 2 3 4 5 6 7 8 9 10 11 | &НаСервере Процедура ЗаписьВерсииДанных() Данные = Справочники.Справочник1.НайтиПоНаименованию("Элемент1").ПолучитьОбъект(); ДатаСоздания = '20180101'; Пользователь = ПользователиИнформационнойБазы.НайтиПоИмени("Администратор"); ИсторияДанных.ЗаписатьВерсию(Данные, ДатаСоздания, Пользователь.УникальныйИдентификатор, Пользователь.Имя, Пользователь.ПолноеИмя, ВидИзмененияДанных.Добавление, "Тестируем запись версий"); КонецПроцедуры |
Получение списка версий
Легко представить, что при интенсивной работе пользователей в информационной базе может храниться очень значительное количество версий объектов. Следовательно для анализа истории данных скорее всего потребуется гибкий инструмент позволяющий нужные версии. Таким инструментом выступает метод ВыбратьВерсии(). Этот метод позволяет указать критерии отбора (первый параметр — Отбор).
При заполнении этих критериев следует учитывать некоторые особенности:
- Необходимо указать один из параметров — Метаданные или Данные, можно указать оба, но только в том случае, когда метаданные параметра Данные совпадают со значением параметра Метаданные;
- Перед получением версий конкретного объекта рекомендуется выполнить обновление истории по этому объекту — ОбновитьИсторию(СсылкаНаОбъект);
- Для отбора по пользователю используется идентификатор пользователя, который можно получить с помощью метода УникальныйИдентификатор() объекта ПользовательИнформационнойБазы;
- Параметр ИзменениеЗначенийПолей позволяет отобрать только те версии в которых изменялись значения указанных полей;
- Если на значения полей требуется наложить конкретные условия, то поможет параметр ЗначенияПолей.
Полную информацию о доступных параметрах отбора можно найти в синтаксис помощнике.
Получим список версий конкретного объекта, в которых изменялся указанный реквизит.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | &НаСервере Процедура ВыбратьВерсииДанных() СсылкаНаОбъект = Справочники.Справочник1.НайтиПоНаименованию("Элемент1"); Отбор = Новый Структура; Отбор.Вставить("Данные", СсылкаНаОбъект); СписокПолей = Новый Массив; СписокПолей.Добавить("Реквизит1"); Отбор.Вставить("ИзменениеЗначенийПолей", СписокПолей); //Результатом метода будет таблица значений //мы можем настроить ее колонки //отсортировать в нужном порядке //и ограничить количество выбраных версий Версии = ИсторияДанных.ВыбратьВерсии(Отбор, "НомерВерсии, Дата, ИмяПользователя, Комментарий", "НомерВерсии Убыв", 100); КонецПроцедуры |
Теперь получим список версий конкретного объекта в которых значение реквизита «Реквизит1» равняется «123» или «321».
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | &НаСервере Процедура ВыбратьВерсииДанных() СсылкаНаОбъект = Справочники.Справочник1.НайтиПоНаименованию("Элемент1"); Отбор = Новый Структура; Отбор.Вставить("Данные", СсылкаНаОбъект); Условие1 = Новый Структура; Условие1.Вставить("Поле", "Реквизит1"); Условие1.Вставить("ЗначениеПослеИзменения", "123"); Условие2 = Новый Структура; Условие2.Вставить("Поле", "Реквизит1"); Условие2.Вставить("ЗначениеПослеИзменения", "321"); ЗначенияПолей = Новый Массив; ЗначенияПолей.Добавить(Условие1); ЗначенияПолей.Добавить(Условие2); Отбор.Вставить("ЗначенияПолей", ЗначенияПолей); Версии = ИсторияДанных.ВыбратьВерсии(Отбор, "НомерВерсии, Дата, ИмяПользователя, Комментарий", "НомерВерсии Убыв"); КонецПроцедуры |
Получение данных версии
Основным предназначением истории данных является получение данных объекта требуемой версии. Сделать это можно при помощи метода СформироватьПоВерсии(), для получения данных нужно указать ссылку на объект (или ключ записи) и номер версии. В результате мы получим объект соответствующего типа, который можно записать в базу.
1 2 3 4 5 6 7 8 9 10 11 12 | &НаСервере Процедура ПолучениеДанныхВерсии() СсылкаНаОбъект = Справочники.Справочник1.НайтиПоНаименованию("Элемент1"); //определим номер версии как в примере выше НомерВерсии = ОпределитьНомерВерсии(); //получаем объект нужной версии и записываем его СпрОбъект = ИсторияДанных.СформироватьПоВерсии(СсылкаНаОбъект, НомерВерсии); //данные версии будут записаны в текущий объект СпрОбъект.Записать(); КонецПроцедуры |
У разработчика имеется возможность вмешаться в процесс формирования восстановленного объекта, для это в модуле объекта (или модуле набора записей) реализовано событие ОбработкаФормированияПоВерсииИсторииДанных().
В модуле формы также имеется возможность понять, что открывается не актуальная версия объекта, для этого реализован параметр формы НомерВерсииПереходаНаВерсиюИсторииДанных, который при открытии с актуальными данными равен Неопределено, а в остальных случаях содержит номер версии открываемых данных.
Если нет необходимости получать данные версии в виде объекта требуемого типа, то можно получить данные версии в виде структуры, где ключ — имя реквизита, а значение — значение реквизита.
1 2 3 4 5 6 7 8 9 10 | &НаСервере Процедура ПолучениеДанныхВерсии() СсылкаНаОбъект = Справочники.Справочник1.НайтиПоНаименованию("Элемент1"); НомерВерсии = ОпределитьНомерВерсии(); //получаем данные версии в виде структуры СтруктураДанных = ИсторияДанных.ПолучитьДанныеВерсии(СсылкаНаОбъект, НомерВерсии); Сообщить(СтруктураДанных.Реквизит1) КонецПроцедуры |
И, наконец, имеется возможность получить метаданные версии в виде структуры.
1 2 3 4 5 6 7 8 9 10 11 | &НаСервере Процедура ПолучениеДанныхВерсии() СсылкаНаОбъект = Справочники.Справочник1.НайтиПоНаименованию("Элемент1"); НомерВерсии = ОпределитьНомерВерсии(); //получаем метаданные версии в виде структуры СтруктураДанных = ИсторияДанных.ПолучитьМетаданные(СсылкаНаОбъект, НомерВерсии); Сообщить(СтруктураДанных.Представление); Сообщить(СтруктураДанных.Поля.Реквизит1) КонецПроцедуры |
Сравнение версий
Одной из основных задач при работе с историей данных является сравнение различных версий объекта и выявление разницы между ними. Делается это при помощи метода ПолучитьРазличияВерсий().
1 2 3 4 5 6 7 8 9 10 | &НаСервере Процедура СравнениеВерсий(НомерВерсииПослеИзменений, НомерВерсииДоИзменений) СсылкаНаОбъект = Справочники.Справочник1.НайтиПоНаименованию("Элемент1"); //сначала указываем номер версии после изменений //затем номер версии до изменений //это важно РазличияВерсий = ИсторияДанных.ПолучитьРазличияВерсий(СсылкаНаОбъект, НомерВерсииПослеИзменений, НомерВерсииДоИзменений); КонецПроцедуры |
В результате получим структуру описывающую различия между версиями, например такую:
Но следует помнить, что система не будет производить никакого анализа и никакого приведения типов, интерпретация результата полностью возложена на разработчика.
Удаление версий
В случае необходимости можно легко удалить некоторые (или все) версии объектов хранящиеся в информационной базе.
1 2 3 4 5 6 7 8 9 10 11 | &НаСервере Процедура УдалениеВерсий() СсылкаНаОбъект = Справочники.Справочник1.НайтиПоНаименованию("Элемент1"); //удаляем версии с номера 1 по номер 3 ИсторияДанных.УдалитьВерсии(СсылкаНаОбъект, 1, 3); //удаляем все версии с начала года ИсторияДанных.УдалитьВерсии(СсылкаНаОбъект, НачалоГода(ТекущаяДата()), ТекущаяДата()); //удаляем все историю указанного справочника ИсторияДанных.УдалитьВерсии(Метаданные.Справочники.Справочник1); КонецПроцедуры |
Прочие операции
В числе прочих операций рассмотрим упоминавшееся уже неоднократно обновление истории, а также комментирование версий.
1 2 3 4 5 6 7 8 9 10 11 | &НаСервере Процедура ПрочиеОперации() СсылкаНаОбъект = Справочники.Справочник1.НайтиПоНаименованию("Элемент1"); //обновляем историю по конкретному объекту ИсторияДанных.ОбновитьИсторию(СсылкаНаОбъект); //обновляем историю во всей базе ИсторияДанных.ОбновитьИсторию(); //записываем коментарий для версии объекта с номером 1 ИсторияДанных.ЗаписатьКомментарий(СсылкаНаОбъект, 1, "комментарий"); КонецПроцедуры |
Кроме этого имеется возможность указать комментарий версии непосредственно во время записи объекта. Для этого в модуле объекта или в модуле набора записей регистра сведений реализован метод УстановитьКомментарийВерсииИсторииДанных().
На этом все, надеюсь, что эта статья была Вам полезна.
Загрузка...
Есть некий реквизит в табличной части документа. В конфигураторе у реквизита стоит Использовать в истории данных. Проверяю перед записью документа этот реквизит командой Метаданные.Документы.Спецификация.ТабличныеЧасти.Товары.Реквизиты.Найти(«ИдентификаторСтроки»).ИсторияДанных — пишет Использовать.
Но содержимое этого реквизита не записывается в версию — пустая строка, хотя в документе реквизит заполнен.
С чем это может быть связано? И как с этим бороться?
Документ добавлен в расширении. Может быть, с этим связаны какие-то нюансы. Другие реквизиты в версию записываются, хотя, не все — есть еще несколько, которые записываются, как пустые.