В практике администраторов и разработчиков 1С нередко случается классическая форс-мажорная ситуация: пользователь перепутал ярлыки баз и в течение всего рабочего дня усердно вносил, правил и проводил документы в резервной копии вместо рабочей базы. Когда ошибка обнаруживается, перед специалистом встает задача оперативно и безопасно перенести сотни новых и измененных документов в «живую» базу.
Проблема осложняется тем, что документы были не просто созданы с нуля, но и изменены «задним числом». Ручной выбор сотен объектов в обработках выгрузки неэффективен и чреват человеческими ошибками. Рассмотрим подробно профессиональные методы решения этой задачи: от разбора журнала регистрации до использования планов обмена и прямого COM-соединения, а также проанализируем критически важные аспекты сохранения ссылочной целостности данных.
Если в базе-копии велась запись системных событий, то самым быстрым и точным способом локализации измененных документов является анализ журнала регистрации. Разберем по шагам, как автоматизировать этот процесс.
Для начала нам необходимо программно прочитать журнал регистрации в копии базы за требуемый период, отфильтровав события по конкретному пользователю и действиям над данными (изменение, добавление).
Ниже представлен пример кода, который выбирает измененные объекты и помещает их в массив для последующей передачи в стандартный механизм выгрузки:
// Создаем фильтр для чтения журнала регистрации
Фильтр = Новый Структура;
Фильтр.Вставить("ДатаНачала", НачалоДня(ТекущаяДата())); // Укажите нужную дату начала
Фильтр.Вставить("ДатаОкончания", КонецДня(ТекущаяДата()));
Фильтр.Вставить("Пользователь", "ИмяПользователя"); // Имя виновника торжества
// Отбираем только события изменения данных
МассивСобытий = Новый Массив;
МассивСобытий.Добавить("_$Data$_.Modify");
МассивСобытий.Добавить("_$Data$_.New");
Фильтр.Вставить("Событие", МассивСобытий);
ТаблицаСобытий = Новый ТаблицаЗначений;
ВыгрузитьЖурналРегистрации(ТаблицаСобытий, Фильтр, "Данные, ПредставлениеДанных, ИмяПользователя");
// Формируем массив уникальных ссылок на измененные документы
МассивСсылок = Новый Массив;
Для Каждого СтрокаЖР Из ТаблицаСобытий Цикл
Если Справочники.ТипВсеСсылки().СодержитТип(ТипЗнч(СтрокаЖР.Данные))
Или Документы.ТипВсеСсылки().СодержитТип(ТипЗнч(СтрокаЖР.Данные)) Тогда
Если МассивСсылок.Найти(СтрокаЖР.Данные) = Неопределено Тогда
МассивСсылок.Добавить(СтрокаЖР.Данные);
КонецЕсли;
КонецЕсли;
КонецЦикла;
Получив данный массив ссылок МассивСсылок в копии базы, мы можем доработать стандартную обработку ВыгрузкаЗагрузкаДанныхXML с диска ИТС, передав этот список в качестве отбора для выгрузки. После загрузки XML-файла в рабочую базу измененные документы появятся на своих местах.
Если вы не хотите писать собственный код для парсинга журнала регистрации, можно воспользоваться штатными интерактивными возможностями обработки «Выгрузка и загрузка данных XML». Многие специалисты забывают о наличии в ней механизма произвольных запросов.
Выполним следующие шаги для настройки выгрузки:
Документ.РеализацияТоваровУслуг), установив отборы по реквизиту Ответственный (или Автор) и по периоду изменения:
ВЫБРАТЬ
Ссылка
ИЗ
Документ.РеализацияТоваровУслуг
ГДЕ
Проведен = ИСТИНА
И Ответственный = &Пользователь
И Дата МЕЖДУ &ДатаНачала И &ДатаОкончания
Обработка автоматически сформирует список выгружаемых объектов на основе результата выполнения этого запроса. Этот метод отлично подходит, если изменения вносились точечно в известные виды документов.
Проанализируем еще одну альтернативу ручному поиску — использование таблиц регистрации изменений (планов обмена). Если в вашей конфигурации настроена регулярная синхронизация данных (например, в рамках РИБ или обмена с другими конфигурациями), платформа 1С автоматически фиксирует любые модификации объектов.
Чтобы задействовать этот механизм, выполним следующие действия:
ПланыОбмена.ВыбратьИзменения().Если обе базы (копия и рабочая) находятся в одной локальной сети и у вас есть к ним административный доступ, можно обойтись без промежуточных XML-файлов. Мы можем написать внешнюю обработку, которая запустится в рабочей базе, подключится к копии через COMConnector, найдет нужные документы и перенесет их напрямую.
Пример алгоритма прямого переноса через COM-соединение:
// Инициализируем подключение к базе-копии
Connector = Новый COMОбъект("V83.COMConnector");
ПараметрыПодключения = "Srvr=""ServerName"";Ref=""CopyDB"";Usr=""Admin"";Pwd=""Password"";";
Попытка
БазаКопия = Connector.Connect(ПараметрыПодключения);
Исключение
Сообщить("Не удалось подключиться к копии базы: " + ОписаниеОшибки());
Возврат;
КонецПопытки;
// Запрашиваем измененные документы в базе-копии
ЗапросКопии = БазаКопия.NewObject("Запрос");
ЗапросКопии.Текст =
"ВЫБРАТЬ
| Ссылка,
| УникальныйИдентификатор
|ИЗ
| Документ.РеализацияТоваровУслуг
|ГДЕ
| Дата >= &ДатаНачала";
ЗапросКопии.SetParameter("ДатаНачала", НачалоДня(ТекущаяДата()));
Выборка = ЗапросКопии.Execute().Select();
Пока Выборка.Next() Цикл
// Ищем документ в рабочей базе по Уникальному Идентификатору (GUID)
UID = Новый УникальныйИдентификатор(Выборка.УникальныйИдентификатор);
ДокРабочий = Документы.РеализацияТоваровУслуг.ПолучитьСсылку(UID);
// Получаем XML-представление объекта из копии и сериализуем его в рабочей базе
// (Или переносим реквизиты напрямую через COM-объект)
// ...
КонецЦикла;
Примечание: Если вы работаете на 64-разрядном сервере приложений 1С, использование COM-соединения может вызвать сложности из-за различий в разрядности библиотек. В современных реалиях более технологичным решением является использование HTTP-сервисов для обмена данными между базами.
При массовом переносе измененных документов из копии в рабочую базу неопытный программист рискует нарушить целостность данных и затереть важные правки коллег. Разберем ключевые опасности и способы их минимизации.
Пользователь в течение дня мог не только создавать документы, но и заводить новые элементы связанных справочников: «Контрагенты», «Номенклатура», «Договоры контрагентов» и т.д. Если выгрузить исключительно документы, то в рабочей базе реквизиты, ссылающиеся на эти новые элементы, превратятся в битые ссылки со значением «<Объект не найден>».
Решение: При настройке параметров выгрузки в обработке XML обязательно активируйте опцию Определить данные, выгружаемые по ссылке. Это заставит систему проанализировать структуру выгружаемых документов и принудительно добавить в файл выгрузки все новые элементы справочников, на которые ссылаются переносимые документы.
Представим ситуацию: пользователь правил старый документ в копии базы. В это же время другой бухгалтер в рабочей базе открыл этот же документ и внес свои, актуальные изменения. При слепой загрузке XML-файла из копии, изменения, сделанные в рабочей базе, будут безвозвратно затерты старыми данными из копии.
Решение: Перед загрузкой объектов необходимо сопоставлять версию объекта или дату/время его последнего изменения в обеих базах. Если в конфигурации включена подсистема «Версионирование объектов» из библиотеки стандартных подсистем (БСП), перед записью загружаемого объекта сверяйте историю версий, чтобы не допустить перезаписи более новых данных старыми.
При переносе новых документов в рабочую базу может возникнуть конфликт номеров, если за время отсутствия синхронизации в рабочей базе уже были созданы другие документы с такими же номерами.
Решение: В коде загрузки или сразу после завершения импорта необходимо запустить обработку перенумерации документов, у которых метод Записать() вызвал ошибку из-за неуникальности номера. Для программной перенумерации можно использовать стандартный метод УстановитьНовыйНомер() для конфликтующих объектов.