Добрый день!
Про настройки хранения истории данных написано много. Но мало информации о том, как же это все работает. Итак, при включении режима использования истории данных,
все реквизиты объекта записываются в метаданные, но для того чтобы увидеть сохраненную версию, необходимо выполнить команду
ИсторияДанных.ОбновитьИсторию();
Данная команда выполняется только с правами Администратор.
Если необходимо для конкретного объекта создать версию данных принудительно, то необходимо выполнить после записи объекта код:
Данные=<Ссылка на объект>.ПолучитьОбъект();
Пользователь=ПользователиИнформационнойБазы.ТекущийПользователь();
ИсторияДанных.ЗаписатьВерсию(Данные,ТекущаяДата(),Пользователь.УникальныйИдентификатор,Пользователь.Имя,Пользователь.ПолноеИмя,ВидИзмененияДанных.Изменение);
Так как же это все таки работает???
Все версии данных, при сохранении объектов попадают в очередь (таблица dbo._DataHistoryQueue0 на сервере SQL), и накапливаются там, пока не выполнится команда
ИсторияДанных.ОбновитьИсторию();
Далее записи перемещаются в dbo._DataHistoryVersions, собственно из этой таблицы мы и видим данные, когда заходим в клиенте в раздел «История изменений»
Вроде бы ничего сложного, можно пользоваться.
Оказывается, есть нюансы:
Задача:
А) Необходимо вести историю данных, причем сохранять изменения, которые делали пользователи, а не регламентные задания.
Б) Так же необходимо учесть, если объект пересоздается в другом месте БД, необходимо перенести и его историю. Например: оборудование демонтировали. В БД есть два объекта 1) Оборудование подразделения и 2) Демонтированное оборудование подразделения. При демонтаже в первом объекте запись удаляется, а во-втором создается путем копирования части реквизитов (структуры объектов не одинаковые).
Решение:Для решения пункта А) нам необходимо в объектах использовать процедуру
Процедура ПослеЗаписи(ПараметрыЗаписи)
Данные=<Ссылка на объект>.ПолучитьОбъект();
Пользователь=ПользователиИнформационнойБазы.ТекущийПользователь();
ИсторияДанных.ЗаписатьВерсию(Данные,ТекущаяДата(),Пользователь.УникальныйИдентификатор,Пользователь.Имя,Пользователь.ПолноеИмя,ВидИзмененияДанных.Изменение);
КонецПроцедуры
, где Ссылка на объект – ссылка на объект, для которого необходимо записать версию, т.е. объект, которые мы только что записали.
Почему после записи?
Потому что версия формируется не из формы, а из сохраненной записи БД.
Почему не используется
ИсторияДанных.ОбновитьИсторию();
?
Потому что изменения, вызванные регламентными заданиями (например перезапись объекта), если таковые имеются, создадут версию данных. При каждом выполнении регламентного задания будет создаваться версия данных и помещаться в очередь. Соответственно при выполнении
ИсторияДанных.ОбновитьИсторию();
все эти версии будут привязаны к объекту.
Для решения Б) нам придется немного схитрить. Дело в том, что готовой функции переноса истории с объекта в объект нет. Так что будем переписывать историю
После записи во-второй объект («Демонтированное оборудование подразделения»), нам необходимо его получить и добавить историю, которая была у объекта Источника:
ДанныеИсточника=<Ссылка на объект источник>;
Демонтаж.Записать();
Объект= ДанныеИсточника.ПолучитьОбъект();
Отбор = Новый Структура;
Отбор.Вставить("Данные", Объект.Ссылка);
Версии = ИсторияДанных.ВыбратьВерсии(Отбор);
ДанныеПриемника=Справочники.ДемонтированноеОборудование.НайтиПоКоду(Демонтаж.Код).ПолучитьОбъект();
Пользователь=ПользователиИнформационнойБазы.ТекущийПользователь();
Для Каждого Строка Из Версии Цикл
Строка.Данные= ДанныеПриемника;
ИсторияДанных.ЗаписатьВерсию(Строка.Данные,Строка.Дата,Строка.Пользователь,Строка.ИмяПользователя,Строка.ПолноеИмяПользователя,Строка.ВидИзмененияДанных,Строка.Комментарий,Строка.Транзакция,Строка.Узел);
КонецЦикла;
, где Ссылка на объект – ссылка на объект источника, историю которого мы хотим передать новому объекту.
ВАЖНО!!!
После переноса истории данных, во-втором объекте будут видны только те поля истории, которые совпадают по наименованию и типу с первым объектом.
Поля, которые нужны только для отображения истории первого объекта, и не используются во-втором объекте можно скрыть от пользователей и не заполнять при переносе из первого объекта.
Вроде бы задача решена, но что нам делать с очередью ИсторииДанных, которая продолжает расти, увеличивая нашу базу не по дням, а по часам.
К сожалению, во встроенной функции ИсторияДанных такой команды нет, поэтому пришлось делать костыльное решение. В SQL создал плановое задание из двух шагов:
Use <имя БД>
truncate table dbo._DataHistoryQueue0
USE [<имя БД>]
GO
DBCC SHRINKDATABASE(N'<имя БД>' )
GO
Первый шаг, чистить таблицу очереди истории данных
Второй шаг, сжимает БД.
Если второй шаг не выполнять, БД не уменьшится в размерах.
В итоге размер БД сократился в 20 раз. Именно столько накопилось в очереди за 2 месяца использования истории данных.