Перенос данных между информационными базами — одна из наиболее часто встречающихся задач у разработчиков 1С. Ситуация осложняется, когда базы имеют разные релизы конфигураций, а переносимый регистр сведений является подчиненным регистратору. В данной статье мы подробно разберем, как восстановить утерянные данные, рассмотрим программные методы синхронизации и проанализируем различные подходы к решению этой задачи.
Представим ситуацию: в базе-источнике существуют записи в регистре сведений ШтрихкодыОС. После серии обновлений в базе-приемнике эти данные оказались утеряны. Нам необходимо «перекинуть» записи из старой копии в рабочую базу. Проблема в том, что регистр может быть подчинен документам (например, ПринятиеКУчетуОС или ОперацияБух), которых в новой базе может не быть в идентичном виде, либо ссылки на них могут отличаться — задачу решает быстрый поиск и удаление битых ссылок в базе.
Рассмотрим наиболее гибкий программный метод — использование COMConnector. Этот способ позволяет подключиться из одной базы к другой «на лету» и прочитать данные напрямую, хотя для обмена между сильно измененными конфигурациями существуют и более комплексные решения, например, универсальный перенос данных по технологии COM+HTTP. Проанализируем пример кода, который выполняет подключение и выборку данных.
Для начала нам необходимо инициализировать соединение с базой-источником:
ПараметрыСоединения = "Srvr=""ServerName"";Ref=""BaseName"";Usr=""Admin"";Pwd=""Password"";";
COMСоединитель = Новый COMОбъект("V83.COMConnector");
Попытка
БазаИсточник = COMСоединитель.Connect(ПараметрыСоединения);
Исключение
Сообщить("Ошибка подключения: " + ОписаниеОшибки());
Возврат;
КонецПопытки;
После успешного подключения мы можем выполнить запрос к регистру сведений в базе-источнике. Выясним причину, почему важно использовать именно запрос: это позволяет отобрать только нужные записи и сразу получить необходимые поля (например, Штрихкод и ОсновноеСредство).
ТекстЗапроса =
"ВЫБРАТЬ
| Штрихкоды.ОсновноеСредство.Код КАК КодОС,
| Штрихкоды.Штрихкод КАК Штрихкод
|ИЗ
| РегистрСведений.ШтрихкодыОС КАК Штрихкоды";
ЗапросИсточник = БазаИсточник.NewObject("Запрос");
ЗапросИсточник.Текст = ТекстЗапроса;
Выборка = ЗапросИсточник.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
// Поиск объекта в текущей базе по коду
СсылкаОС = Справочники.ОсновныеСредства.НайтиПоКоду(Выборка.КодОС);
Если Не СсылкаОС.Пустая() Тогда
// Запись в регистр текущей базы
МенеджерЗаписи = РегистрыСведений.ШтрихкодыОС.СоздатьМенеджерЗаписи();
МенеджерЗаписи.ОсновноеСредство = СсылкаОС;
МенеджерЗаписи.Штрихкод = Выборка.Штрихкод;
МенеджерЗаписи.Записать();
КонецЕсли;
КонецЦикла;
Если прямое сетевое соединение между базами невозможно, разберем способ через выгрузку в промежуточный файл. Для автоматизации этого процесса вместо ручного написания кода можно использовать готовые решения, например, универсальную выгрузку-загрузку с шифрованием данных (поможет универсальная выгрузка и загрузка данных через COM) Использование JSON в современной платформе 8.3 является более быстрым и менее требовательным к ресурсам, чем XML.
Шаг 1. Выгрузка из источника:
Создадим массив структур, где каждая структура — это запись регистра, и запишем его в файл.
ЗаписиДляВыгрузки = Новый Массив;
Выборка = РегистрыСведений.ШтрихкодыОС.Выбрать();
Пока Выборка.Следующий() Цикл
СтруктураЗаписи = Новый Структура("КодОС, Штрихкод", Выборка.ОсновноеСредство.Код, Выборка.Штрихкод);
ЗаписиДляВыгрузки.Добавить(СтруктураЗаписи);
КонецЦикла;
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.ОткрытьФайл("C:\temp\barcodes.json");
ЗаписатьJSON(ЗаписьJSON, ЗаписиДляВыгрузки);
ЗаписьJSON.Закрыть();
Шаг 2. Загрузка в приемник:
Проанализируем процесс чтения. Здесь важно реализовать поиск ссылочных объектов, так как UUID (уникальные идентификаторы) в разных базах могут не совпадать.
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.ОткрытьФайл("C:\temp\barcodes.json");
МассивДанных = ПрочитатьJSON(ЧтениеJSON);
ЧтениеJSON.Закрыть();
Для Каждого СтрокаДанных Из МассивДанных Цикл
СсылкаОС = Справочники.ОсновныеСредства.НайтиПоКоду(СтрокаДанных.КодОС);
Если Не СсылкаОС.Пустая() Тогда
НаборЗаписей = РегистрыСведений.ШтрихкодыОС.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.ОсновноеСредство.Установить(СсылкаОС);
НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.ОсновноеСредство = СсылкаОС;
НоваяЗапись.Штрихкод = СтрокаДанных.Штрихкод;
НаборЗаписей.Записать();
КонецЕсли;
КонецЦикла;
Рассмотрим ситуацию, когда регистр ШтрихкодыОС подчинен регистратору. В этом случае мы не можем просто записать МенеджерЗаписи без указания документа. Если документы-регистраторы отсутствуют в новой базе, у нас есть два пути:
ОперацияБух или специально созданный технический документ ВосстановлениеДанных) и назначаем его регистратором для всех переносимых записей.Посмотрим на пример создания записи с техническим регистратором:
ТехРегистратор = Документы.ОперацияБух.СоздатьДокумент();
ТехРегистратор.Дата = ТекущаяДата();
ТехРегистратор.Содержание = "Восстановление штрихкодов ОС";
ТехРегистратор.Записать();
НаборЗаписей = РегистрыСведений.ШтрихкодыОС.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(ТехРегистратор.Ссылка);
НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.Регистратор = ТехРегистратор.Ссылка;
НоваяЗапись.Период = ТекущаяДата();
НоваяЗапись.ОсновноеСредство = НайденнаяСсылкаОС;
НоваяЗапись.Штрихкод = ЗначениеШтрихкода;
НаборЗаписей.Записать();
Выясним, как упростить задачу без написания сложного кода. Существует стандартная обработка ВыгрузкаЗагрузкаДанныхXML — для сложных задач удобнее универсальная синхронизация данных по COM и XML. Она эффективно работает, если метаданные регистра полностью идентичны.
Важный нюанс: при несовпадении релизов обработка может выдать ошибку. В этом случае можно либо привести базы к одному релизу, либо использовать адаптивную выгрузку и загрузку данных XML, которая позволяет производить обмен между не полностью идентичными конфигурациями.
Проанализируем проблему «битых ссылок». Если в результате переноса или других действий в базе появляются некорректные указатели на объекты, можно применить обработку для поиска и замены битых ссылок. Если же говорить о первопричине, то когда основные средства в базах создавались независимо, их коды могут совпадать, а внутренние идентификаторы — нет. Чтобы гарантировать корректность, рекомендуется использовать поиск по коду или наименованию, как было показано в примерах выше.
Если же базы являются «родственными» (одна — копия другой), можно использовать UUID:
// В базе источнике
СтрокаUUID = Строка(Выборка.ОсновноеСредство.УникальныйИдентификатор());
// В базе приемнике
НовыйUUID = Новый УникальныйИдентификатор(СтрокаUUID);
СсылкаОС = Справочники.ОсновныеСредства.ПолучитьСсылку(НовыйUUID);
Мы рассмотрели несколько способов программного переноса данных регистра сведений. Выбор метода зависит от объема данных и возможности прямого подключения между базами. Наиболее надежным для разового восстановления данных в доработанных регистрах является метод через COM-соединение с поиском ссылок по естественным ключам (код, артикул, наименование).
Помните, что при работе с большими объемами записей (десятки тысяч) следует использовать ЗаблокироватьДанные() и выполнять запись порциями в транзакции, чтобы не вызвать переполнение лога транзакций и не блокировать работу пользователей.