v8: Парциальная регистрация изменений в базе данных Ключевые слова: протокол,журнал регистрации,регистрация
Протоколирование.
К сожалению, в стандартном журнале регистрации событий 1С есть возможность только узнать, менялся ли объект, но нет возможности определить, что именно менялось в объекте - какие реквизиты менялись.
Однако можно внедрить в событие перед записью объекта свой обработчик, который будет сравнивать состояние объекта в базе данных с состоянием записываемого объекта и находить различия.
При наличии интереса подобные вещи можно внедрять и в модуль записи набора записей регистра сведений, например, но зачастую движения регистра сведений связаны с состоянием документа-регистратора, поэтому лучше ограничиться контролем записи справочников и документов.
Состояние объекта мы получаем из переменной ЭтотОбъект.
Состояние объекта в базе данных мы получаем с помощью выражения ЭтотОбъект.Ссылка.ПолучитьОбъект().
Изменения объекта получаем через перебор его реквизитов шапки и табличных частей по метаданным.
Изменения объекта можно представить в виде таблицы со структурой Изменения(ИмяРеквизита, ИмяТЧ, СтрокаТЧ, СтароеЗначение, Значение).
Для реквизитов объекта ИмяТЧ=Неопределено.
Для уменьшения объема протокола нужно сохранять только измененные реквизиты.
Однако в протоколе еще должны содержаться время модификации, имя пользователя и другие желаемые реквизиты окружения. Т.е. окружение представляется структурой вида Событие(Время, Пользователь, Компьютер)
Протокол можно хранить в виде справочника, шапка которого повторяет структуру Событие, а табличная часть содержит таблицу Изменения.
Можно поступить иначе, создав два регистра сведений, в одном из них хранятся События, в другом - Изменения.
Можно конечно связать эти два регистра по времени или даже по времени и изменяемому объекту, но один объект может несколько раз меняться в течении одной секунды, поэтому для связи лучше использовать GUID.
Хотя в принципе можно создать один плоский регистр сведений для Событий и Изменений, если не жалко памяти. Здесь мы выигрываем в записи, т.к. запись ведется только в одну физическую таблицу.
Использование справочника для журнала регистрации.
По идее, использование справочника для журнала регистрации более быстро, т.к. справочник без кода и автонумерации быстрее записывается, чем регистр сведений (не нужно контролировать уникальность). Эта тема пока еще не исследована. Нужно произвести замеры производительности на файловой и SQL версии.
Буферизация.
Однако запись данных в протокол при каждом изменении объекта несколько накладно и тормозит работу с базой.
Рассмотрим буферизацию.
При записи объекта изменения накапливаются в глобальной таблице значений.
Периодически эта таблица значений сбрасывается в базу данных и очищается.
Единственный недостаток схемы - приложение может рухнуть, а вместе с ним и буфер.
Можно отслеживать падения, если после сброса буфера в базу данных делать в базе данных запись о том, что стартовал новый буфер. При следующем сбросе эту запись очищать. Тогда зависшие записи будут сообщать нам о несделанных изменениях.
Можно сбрасывать изменения в локальный файл или использовать другие ухищрения виндоус, например область памяти клиента и т.п.
Буферизация в журнале регистрации.
Буферизация в таблице значений имеет недостатко - данные могут потеряться при падении базы.
Поэтому лучше всего использовать буферизацию в журнале регистрации, т.е. запись об изменениях делается в журнале регистрации, где структура изменений кодируется в виде внутренней строки.
Затем периодически делается перенос этих записей в таблицу регистрации изменений в базе данных.
Реализация в коде
Рассмотрим реализацию без буферизации, с двумя связанными по GUID регистрами сведений.
Используется функция сравнения двух объектов: Книга знаний: v8: Функция сравнения двух объектов одного типа
Функция п_ЗафиксироватьИзменениеОбъекта(Объект, РежимЗаписи=Неопределено, РежимПроведения=Неопределено) Экспорт
Ссылка=ДокументСсылкаДатьТочную(Объект);
//Фиксируем факт записи
ГУИД=Новый УникальныйИдентификатор();
Ключ=GUIDВСтроку(ГУИД);
МЗ=РегистрыСведений.п_ЛогИзменений.СоздатьМенеджерЗаписи();
МЗ.Дата=ТекущаяДата();
МЗ.Пользователь=ПараметрыСеанса.ТекущийПользователь;
МЗ.Объект=Ссылка;
МЗ.РежимЗаписи=РежимЗаписи;
МЗ.РежимПроведения=РежимПроведения;
МЗ.Ключ=Ключ;
МЗ.Новый=ЗначениеНеЗаполнено(Объект.Ссылка);
МЗ.ОбъектСтрокой=Строка(Объект);
МЗ.Записать();
//Сравниваем старый и новый объекты - получаем таблицу разниц
Если ЗначениеНеЗаполнено(Объект.Ссылка) Тогда
СравнОбъект=Объект;
Иначе
СравнОбъект=Объект.Ссылка.ПолучитьОбъект();
КонецЕсли;
Т=СравнитьДваОбъекта(СравнОбъект, Объект);
Если Т.Количество()>0 Тогда
НЗ=РегистрыСведений.п_ЛогИзмененийТЧ.СоздатьНаборЗаписей();
НЗ.Отбор.КлючВладельца.Значение=Ключ;
НЗ.Отбор.КлючВладельца.ВидСравнения=ВидСравнения.Равно;
НЗ.Отбор.КлючВладельца.Использование=истина;
Для Каждого Стр Из Т Цикл
МЗ=НЗ.Добавить();
МЗ.КлючВладельца=Ключ;
МЗ.Реквизит=Стр.Реквизит;
МЗ.НомСтроки=Стр.НомерСтроки;
МЗ.ТабличнаяЧасть=Стр.ТабличнаяЧасть;
МЗ.Значение1=Стр.Значение1;
МЗ.Значение2=Стр.Значение2;
МЗ.ТипЗнч1=ТипЗнч(Стр.Значение1);
МЗ.ТипЗнч2=ТипЗнч(Стр.Значение2);
МЗ.ЗначениеСтрокой1=Строка(Стр.Значение1);
МЗ.ЗначениеСтрокой2=Строка(Стр.Значение2);
КонецЦикла;
НЗ.Записать();
КонецЕсли;
КонецФункции
Функция ДокументСсылкаДатьТочную(Объект) Экспорт
Перем Ссылка, Вид;
Ссылка=Объект.Ссылка;
Если Ссылка.Пустая() Тогда
Ссылка = Объект.ПолучитьСсылкуНового();
Если Ссылка.Пустая() Тогда
Вид=Объект.Метаданные().Имя;
Ссылка = Документы[Вид].ПолучитьСсылку();
Объект.УстановитьСсылкуНового(Ссылка);
КонецЕсли;
КонецЕсли;
Возврат Ссылка;
КонецФункции
Структура регистров
- РегистрыСведений.п_ЛогИзменений
Имя: "п_ЛогИзменений"
Синоним: "Лог изменений"
Комментарий: ""
Подсистемы:
"Конфигурация.УправлениеПроизводственнымПредприятием"
СпособРедактирования: "ВСписке"
ОсновнаяФормаЗаписи: ""
ОсновнаяФормаСписка: "РегистрСведений.п_ЛогИзменений.Форма.ФормаСписка"
ПериодичностьРегистраСведений: "Непериодический"
РежимЗаписи: "Независимый"
ОсновнойОтборПоПериоду: "Ложь"
ВключатьСправкуВСодержание: "Ложь"
- РегистрыСведений.п_ЛогИзменений.Ресурсы.Описание
Имя: "Описание"
Синоним: "Описание"
Комментарий: ""
Тип:
"Строка(0)"
Индексирование: "НеИндексировать"
- РегистрыСведений.п_ЛогИзменений.Ресурсы.РежимЗаписи
Имя: "РежимЗаписи"
Синоним: "Режим записи"
Комментарий: ""
Тип:
"Строка(32)"
Индексирование: "НеИндексировать"
- РегистрыСведений.п_ЛогИзменений.Ресурсы.РежимПроведения
Имя: "РежимПроведения"
Синоним: "Режим проведения"
Комментарий: ""
Тип:
"Строка(32)"
Индексирование: "НеИндексировать"
- РегистрыСведений.п_ЛогИзменений.Ресурсы.Новый
Имя: "Новый"
Синоним: "Новый"
Комментарий: ""
Тип:
"Булево"
Индексирование: "НеИндексировать"
- РегистрыСведений.п_ЛогИзменений.Ресурсы.ОбъектСтрокой
Имя: "ОбъектСтрокой"
Синоним: "Объект строкой"
Комментарий: ""
Тип:
"Строка(0)"
Индексирование: "НеИндексировать"
- РегистрыСведений.п_ЛогИзменений.Измерения.Дата
Имя: "Дата"
Синоним: "Дата"
Комментарий: ""
Тип:
"Дата(ДатаВремя)"
Ведущее: "Ложь"
ОсновнойОтбор: "Истина"
ЗапрещатьНезаполненныеЗначения: "Ложь"
Индексирование: "ИндексироватьСДопУпорядочиванием"
- РегистрыСведений.п_ЛогИзменений.Измерения.Пользователь
Имя: "Пользователь"
Синоним: "Пользователь"
Комментарий: ""
Тип:
"СправочникСсылка.Пользователи"
Ведущее: "Истина"
ОсновнойОтбор: "Истина"
ЗапрещатьНезаполненныеЗначения: "Ложь"
Индексирование: "НеИндексировать"
- РегистрыСведений.п_ЛогИзменений.Измерения.Объект
Имя: "Объект"
Синоним: "Объект"
Комментарий: ""
Тип:
"ЛюбаяСсылка"
Ведущее: "Истина"
ОсновнойОтбор: "Истина"
ЗапрещатьНезаполненныеЗначения: "Ложь"
Индексирование: "НеИндексировать"
- РегистрыСведений.п_ЛогИзменений.Измерения.Ключ
Имя: "Ключ"
Синоним: "Ключ"
Комментарий: ""
Тип:
"Строка(32)"
Ведущее: "Ложь"
ОсновнойОтбор: "Истина"
ЗапрещатьНезаполненныеЗначения: "Ложь"
Индексирование: "НеИндексировать"
- РегистрыСведений.п_ЛогИзменений.Формы.ФормаСписка
Имя: "ФормаСписка"
Синоним: "Форма списка"
Комментарий: ""
ВключатьСправкуВСодержание: "Ложь"
- РегистрыСведений.п_ЛогИзмененийТЧ
Имя: "п_ЛогИзмененийТЧ"
Синоним: "Лог изменений ТЧ"
Комментарий: ""
Подсистемы:
"Конфигурация.УправлениеПроизводственнымПредприятием"
СпособРедактирования: "ВСписке"
ОсновнаяФормаЗаписи: ""
ОсновнаяФормаСписка: ""
ПериодичностьРегистраСведений: "Непериодический"
РежимЗаписи: "Независимый"
ОсновнойОтборПоПериоду: "Ложь"
ВключатьСправкуВСодержание: "Ложь"
- РегистрыСведений.п_ЛогИзмененийТЧ.Ресурсы.Значение1
Имя: "Значение1"
Синоним: "Значение1"
Комментарий: ""
Тип:
"ЛюбаяСсылка,
Булево,
Строка(10),
Дата(Дата),
Число(10, 0)"
Индексирование: "НеИндексировать"
- РегистрыСведений.п_ЛогИзмененийТЧ.Ресурсы.Значение2
Имя: "Значение2"
Синоним: "Значение2"
Комментарий: ""
Тип:
"ЛюбаяСсылка,
Булево,
Строка(10),
Дата(Дата),
Число(10, 0)"
Индексирование: "НеИндексировать"
- РегистрыСведений.п_ЛогИзмененийТЧ.Ресурсы.ТипЗнч1
Имя: "ТипЗнч1"
Синоним: "Тип значения 1"
Комментарий: ""
Тип:
"Строка(100)"
Индексирование: "НеИндексировать"
- РегистрыСведений.п_ЛогИзмененийТЧ.Ресурсы.ТипЗнч2
Имя: "ТипЗнч2"
Синоним: "Тип значения 2"
Комментарий: ""
Тип:
"Строка(100)"
Индексирование: "НеИндексировать"
- РегистрыСведений.п_ЛогИзмененийТЧ.Ресурсы.ЗначениеСтрокой1
Имя: "ЗначениеСтрокой1"
Синоним: "Значение строкой 1"
Комментарий: ""
Тип:
"Строка(0)"
Индексирование: "НеИндексировать"
- РегистрыСведений.п_ЛогИзмененийТЧ.Ресурсы.ЗначениеСтрокой2
Имя: "ЗначениеСтрокой2"
Синоним: "Значение строкой 2"
Комментарий: ""
Тип:
"Строка(0)"
Индексирование: "НеИндексировать"
- РегистрыСведений.п_ЛогИзмененийТЧ.Измерения.КлючВладельца
Имя: "КлючВладельца"
Синоним: "Ключ владельца"
Комментарий: ""
Тип:
"Строка(32)"
Ведущее: "Ложь"
ОсновнойОтбор: "Истина"
ЗапрещатьНезаполненныеЗначения: "Ложь"
Индексирование: "НеИндексировать"
- РегистрыСведений.п_ЛогИзмененийТЧ.Измерения.Реквизит
Имя: "Реквизит"
Синоним: "Реквизит"
Комментарий: ""
Тип:
"Строка(100)"
Ведущее: "Истина"
ОсновнойОтбор: "Истина"
ЗапрещатьНезаполненныеЗначения: "Ложь"
Индексирование: "НеИндексировать"
- РегистрыСведений.п_ЛогИзмененийТЧ.Измерения.НомСтроки
Имя: "НомСтроки"
Синоним: "Номер строки"
Комментарий: ""
Тип:
"Число(10, 0)"
Ведущее: "Ложь"
ОсновнойОтбор: "Истина"
ЗапрещатьНезаполненныеЗначения: "Ложь"
Индексирование: "НеИндексировать"
- РегистрыСведений.п_ЛогИзмененийТЧ.Измерения.ТабличнаяЧасть
Имя: "ТабличнаяЧасть"
Синоним: "Табличная часть"
Комментарий: ""
Тип:
"Строка(100)"
Ведущее: "Ложь"
ОсновнойОтбор: "Истина"
ЗапрещатьНезаполненныеЗначения: "Ложь"
Индексирование: "НеИндексировать"
Похожие ссылки:
Книга знаний: v8: Регистрация изменений в справочнике |