Дозагрузка измененных данных при помощи КД2

Публикация № 1114082

Разработка - Практика программирования

4
Иногда во время каких-то регламентных действий по обслуживанию базы(например, при обновлении измененной базы на много релизов) требуется обеспечить бесперебойность работы пользователей. Если конфигурации баз до и после идентичны, то тут сам Бог велел воспользоваться обработкой "ВыгрузкаЗагрузкаДанныхXML", либо такой же но с отбором(на Инфостарте есть такая). Но что если конфигурации баз различаются/значительно различаются? Ниже опишу, как вышел из положения я.

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

 Итак, сама задача: есть доработанная база на конфигурации УТАП лохматого релиза(оптовая и розничная торговля алкоголем в одной базе). Обновить надо порядка 15 релизов. Изначально я готовил последний релиз с нашими изменениями и было согласовано с заказчиком, что он самостоятельно обновляется до типовых версий промежуточных релизов по ночам(а днём в это время пользователи работают на типовом функционале) и когда доходит до последнего релиза, мы восстанавливаем все наши изменения. 

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

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

 Первым делом загружаю файлы конфигураций старой и новой базы в КД2 и создаю новую конвертацию данных между ними.  ПКО генерирую автоматически и автоматически же создаю для них ПВД. 

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

 Задача разбивается на две части:

  1. Выбрать только измененные данные с момента снятия копии в в старой базе;
  2. Конвертировать их в новую базу.

 Создаю параметры, которые понадобятся нам для отбора и хранения изменений:

Первую часть можно решить двумя способами:

 Первый способ - через журнал регистрации. Нам надо прочитать изменения начиная с момента создания копии("ДатаНачалаИзменений") и выбрать их в таблицу значений ("ИзмененныеДанные"). Для того, чтоб отобрать изменения из ЖР в таблицу значений, в событии конвертации "ПередВыгрузкойДанных" прописываем заполнение таблицы изменений: 

    ВнешниеДанные = Новый ТаблицаЗначений;
	ФильтрЖурнала = Новый Структура;
	МассивСобытий = Новый  Массив;
    МассивСобытий.Добавить("_$Data$_.Post");
	МассивСобытий.Добавить("_$Data$_.Delete");
    МассивСобытий.Добавить("_$Data$_.Update");
	ФильтрЖурнала.Вставить("ДатаНачала",НачалоДня(Параметры.ДатаНачалаИзменений));	
	ФильтрЖурнала.Вставить("ДатаОкончания",КонецДня(ТекущаяДата()));
    ФильтрЖурнала.Вставить("Событие", МассивСобытий);
    ВыгрузитьЖурналРегистрации(ВнешниеДанные,ФильтрЖурнала);
    ВнешниеДанные.Свернуть("Данные");
	
	Для каждого стр Из ВнешниеДанные Цикл
		ст = ТЗИзменений.Найти(ТипЗнч(стр.Данные));
		Если ст = Неопределено Тогда
			ст          = ТЗИзменений.Добавить();
			ст.Тип      = ТипЗнч(стр.Данные);
			ст.Элементы = Новый Массив;
		КонецЕсли;	
		ст.Элементы.Добавить(стр.Данные); 
		ст.Количество = ст.Количество + 1;
	КонецЦикла;	
		
    Параметры.ИзмененныеДанные = ТЗИзменений.Скопировать();

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

  • Может быть настроено удаление записей журнала регистрации - в этом случае надо договариваться с системным администратором, чтоб он отключил его временно;
  • Из ЖР не удастся извлечь изменения регистров, которые нам тоже нужны.

  Было решено воспользоваться вторым способом - через планы обмена. Я создал отдельный план обмена, в составе которого указал все необходимые объекты(Справочники, Документы, ПланыВидовХарактеристик, РегистрыСведений) с авторегистрацией.

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

 В событии "ПередВыгрузкойДанных" моей конвертации прописал: 

ТЗИзменений = Новый ТаблицаЗначений;
тзИзменений.Колонки.Добавить("Тип");
тзИзменений.Колонки.Добавить("Элементы");
тзИзменений.Колонки.Добавить("Количество",Новый ОписаниеТипа("Число"));

Узел = ПланыОбмена.ФиксацияДанныхДляОбновления.НайтиПоКоду("002");
ЗаписьXML = Новый ЗаписьXML(); 
ЗаписьXML.УстановитьСтроку(); 
ЗапСообщения = ПланыОбмена.СоздатьЗаписьСообщения(); 
ЗапСообщения.НачатьЗапись(ЗаписьXML, Узел); 
Количество = 0;
Выборка = ПланыОбмена.ВыбратьИзменения(Узел, ЗапСообщения.НомерСообщения); 
Пока Выборка.Следующий() Цикл 
	Данные = Выборка.Получить(); 
	Попытка
		Если Найти(Данные.Метаданные().ПолноеИмя(),"Регистр")=0 Тогда
			ст = ТЗИзменений.Найти(ТипЗнч(Данные));
			Если ст = Неопределено Тогда
				ст          = ТЗИзменений.Добавить();
				ст.Тип      = ТипЗнч(Данные);
				ст.Элементы = Новый Массив;
			КонецЕсли;	
			ст.Элементы.Добавить(Данные); 
			ст.Количество = ст.Количество + 1;
		Иначе
			ст = ТЗИзменений.Найти(ТипЗнч(Данные));
			Если ст = Неопределено Тогда
				ст          = ТЗИзменений.Добавить();
				ст.Тип      = ТипЗнч(Данные);
				ст.Элементы = Новый Массив;
			КонецЕсли;
			ст.Элементы.Добавить(Данные); 
			ст.Количество = ст.Количество + 1;
		КонецЕсли; 
		Количество = Количество + 1;
	Исключение
		ПланыОбмена.УдалитьРегистрациюИзменений(Узел, Данные);
	КонецПопытки;
КонецЦикла; 

Параметры.ИзмененныеДанные = ТЗИзменений.Скопировать();

ЗапСообщения.ПрерватьЗапись(); 

 Создаю алгоритм, который будет выполняться в событии "ПередОбработкой" в каждом ПВД и отбирать данные из параметра "ИзмененныеДанные":

ЭтоРегистр = Ложь;
	ИмяОбъекта = Правило.Наименование;
	
		Если Найти("Справочники, ПланыВидовХарактеристики, Документы, БизнесПроцессы, Задачи",Строка(Правило.Родитель.Наименование))>0 тогда
			ТипОбъектов = Правило.ОбъектВыборки;
		Иначе  
			ТипОбъектов = Тип("РегистрСведенийНаборЗаписей."+Правило.Наименование);
			ЭтоРегистр = Истина;
		КонецЕсли;	
	
	строкаТипа = Параметры.ИзмененныеДанные.Найти(ТипОбъектов); 
	
	Если СтрокаТипа<>Неопределено Тогда
	    МассивКВыгрузке = СтрокаТипа.Элементы;
		Если ЭтоРегистр Тогда
			Для каждого Элемент Из МассивКВыгрузке Цикл
				НЗ = РегистрыСведений[ИмяОбъекта].СоздатьНаборЗаписей();
				Для каждого Измерение Из Метаданные.РегистрыСведений[ИмяОбъекта].Измерения Цикл
				   НЗ.Отбор[Измерение.Имя].Установить(Элемент.Отбор[Измерение.Имя].Значение);  
				КонецЦикла;	
				НЗ.Прочитать();
				Для каждого Запись Из НЗ Цикл
				 ВыгрузитьПоПравилу(Запись,,,,ИмяПКО);
				КонецЦикла;
			КонецЦикла;
		Иначе	
			ВыборкаДанных = МассивКВыгрузке;				
		КонецЕсли;	
		Сообщить("Выполнена выгрузка по ПВД """+ИмяОбъекта+""". Выгружено "+МассивКВыгрузке.Количество()+" объектов/записей.");
	Иначе	
	    Сообщить("Пропущено ПВД """+ИмяОбъекта+""" - не было найдено ни одного объекта.");	
	КонецЕсли;

  Следующим шагом требуется изменить ПВД всех обрабатываемых объектов(Справочники, Документы, ПланыВидовХарактеристик, РегистрыСведений) в "ПроизвольныйАлгоритм" и присвоить реквизиту "АлгоритмПередОбработкойПравила" посредством групповой обработки значение "Выполнить(Алгоритмы.ПВД_ПередОбработкой);". 

 По-идее, доработка конвертации таким образом, как у меня, необязательна и достаточно выбрать в обработке "Универсальный обмен данными в формате XML" план обмена, из которого необходимо выбирать изменения. Я сначала так пробовал, ещё на стадии отладки правил. Но заметил, чтоб после выгрузки изменений, осуществленной подобным образом у меня пропадают регистрации по изменениям справочников и документов. И закралось подозрение, что не выгружаются изменения регистров сведений. Потому реализовал так как описано выше. Возможно, было бы проще поправить обработку. 

 P.S. Чтоб вы знали - я, как истинно ленивый одинэсник, искал и другие способы попроще, чтоб перенести данные из старой базы в новую. В частности хотел попробовать посредством выгрузки через универсальный формат, но у меня в конфигурации отраслевые документы и потому он не подошел. Думал попробовать обработкой "Универсальная выгрузка/загрузка данных для отличающихся конфигураций (JSON, Такси+ОФ)" от уважаемой  Евгении Карук, но обработка при попытке загрузки первого же документа сказала мне 

Дальше решил судьбу не испытывать.

Буду рад, если мой опыт окажется кому-нибудь полезен!

Спасибо за внимание!

4

См. также

Специальные предложения

Комментарии
Избранное Подписка Сортировка: Древо
1. user-z99999 18 12.09.19 10:54 Сейчас в теме
1) Берем пустую базу без пользователей и обновляем. (пустая база получается из cf-файла рабочей базы)
2) Выгружаем cf-файл. т.е. уже база обновлена.
3) Накатываем cf-файл на тестовую базу и проверяем. Если надо тестируем правила КД 2.0
4) из шага 2 накатываем cf-файл на рабочую базу (Конфигурация - Загрузить конфигурацию из файла)

Покритикуйте такой подход.
2. al_zzz 117 12.09.19 11:06 Сейчас в теме
(1) Я не буду критиковать ваш подход. Сам по сути так делаю, когда изменения касаются лишь структуры. В моём же случае происходит обработка данных в регламентных, запускающихся после обновления. Вот они-то и выполняются очень долго. А если их пропустить, то розничные продажи в обновленной базе не выполняются.
Оставьте свое сообщение