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