При переносе данных между базами 1С администраторы и разработчики часто сталкиваются с непредвиденным поведением внешних обработок. Ситуация, когда запущенная исключительно на выгрузку обработка неожиданно начинает изменять данные в исходной рабочей базе, не просто неприятна, а критична. Если после этого в системе уже успели поработать пользователи, а автоматический обмен (РИБ) разнес поврежденные данные по филиалам, возникает управленческий хаос.
В этой статье мы подробно разберем, почему безобидные на первый взгляд обработки выгрузки модифицируют данные в базе-источнике, как точечно восстановить справочник контрагентов из резервной копии по уникальным идентификаторам (GUID) без отката рабочей базы и как правильно навести порядок в распределенных информационных базах (РИБ).
Для многих технических специалистов кажется парадоксом, что процедура чтения и экспорта данных приводит к перезаписи объектов в источнике. Проанализируем основные технические причины, по которым это происходит в среде 1С:
Записать() у объекта справочника запускает всю цепочку платформенных событий.ПередЗаписью и ПриЗаписи. В этих подписках может быть заложена логика автоматического пересчета наименований по ИНН через внешние сервисы, очистка «лишних» пробелов, автозаполнение кодов или договоров. Это объясняет, почему пострадали не все контрагенты, а только часть, удовлетворяющая определенным условиям подписок.V83.COMConnector): Если выгрузка происходила через COM-соединение напрямую в приемник, в контексте источника создается полноценная сессия. При некорректно написанных обработчиках «После выгрузки» в правилах конвертации данных (КД) код может попытаться переопределить ссылки в источнике или инициализировать создание связанных объектов (например, договоров по умолчанию), что приводит к перезаписи родительского контрагента.Главная сложность в подобной ситуации — пользователи уже отработали в базе целый день. Откатывать всю базу на ночной бэкап нельзя, так как это приведет к потере сотен введенных документов, накладных и оплат. Нам необходимо выполнить точечную реставрацию только испорченных элементов справочника Справочники.Контрагенты, сохранив их внутренние идентификаторы (GUID), чтобы новые документы не потеряли связь с ними.
Рассмотрим два основных способа решения этой задачи.
Этот способ является наиболее гибким, так как позволяет детально контролировать, какие именно реквизиты мы заменяем, и не затереть новых контрагентов, созданных пользователями в течение рабочего дня. Разберем алгоритм по шагам:
Ниже представлен пример программного кода для такой обработки:
Процедура ВосстановитьКонтрагентовИзКопии()
// 1. Инициализируем COM-соединение с резервной копией базы
ПараметрыПодключения = "Srvr=""MyServer"";Ref=""Backup_Base"";Usr=""Admin"";Pwd=""Password"";";
Connector = Новый COMОбъект("V83.COMConnector");
Попытка
БазаКопия = Connector.Connect(ПараметрыПодключения);
Исключение
Предупреждение("Не удалось подключиться к копии базы: " + ОписаниеОшибки());
Возврат;
КонецПопытки;
// 2. Выбираем всех контрагентов из текущей рабочей базы
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Контрагенты.Ссылка КАК Ссылка,
| Контрагенты.Представление КАК Представление
|ИЗ
| Справочник.Контрагенты КАК Контрагенты
|ГДЕ
| НЕ Контрагенты.ЭтоГруппа";
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
КоличествоВосстановленных = 0;
Пока Выборка.Следующий() Цикл
// Получаем GUID текущего контрагента в рабочей базе
ТекущийУИД = Выборка.Ссылка.УникальныйИдентификатор();
СтрокаУИД = Строка(ТекущийУИД);
// Создаем аналогичный GUID в контексте базы-копии
КопияУИД = БазаКопия.NewObject("УникальныйИдентификатор", СтрокаУИД);
СсылкаКопия = БазаКопия.Справочники.Contragents.GetRef(КопияУИД); // Обратите внимание на имя метаданных в копии
// Проверяем, существует ли объект в копии базы
Если БазаКопия.ValueIsFilled(СсылкаКопия) Тогда
// Получаем объект для редактирования в рабочей базе
ОбъектРабочий = Выборка.Ссылка.ПолучитьОбъект();
Изменено = Ложь;
// Построчно сравниваем и восстанавливаем реквизиты
Если ОбъектРабочий.Наименование <> СсылкаКопия.Description Тогда
ОбъектРабочий.Наименование = СсылкаКопия.Description;
Изменено = Истина;
КонецЕсли;
Если ОбъектРабочий.НаименованиеПолное <> СсылкаКопия.НаименованиеПолное Тогда
ОбъектРабочий.НаименованиеПолное = СсылкаКопия.НаименованиеПолное;
Изменено = Истина;
КонецЕсли;
Если ОбъектРабочий.ИНН <> СсылкаКопия.ИНН Тогда
ОбъектРабочий.ИНН = СсылкаКопия.ИНН;
Изменено = Истина;
КонецЕсли;
Если ОбъектРабочий.КПП <> СсылкаКопия.КПП Тогда
ОбъектРабочий.КПП = СсылкаКопия.КПП;
Изменено = Истина;
КонецЕсли;
// Если реквизиты отличались, перезаписываем объект
Если Изменено Тогда
Попытка
// Важно: отключаем обработчики и регистрацию изменений для обмена
ОбъектРабочий.ОбменДанными.Загрузка = Истина;
ОбъектРабочий.Записать();
КоличествоВосстановленных = КоличествоВосстановленных + 1;
Исключение
Сообщить("Не удалось записать контрагента: " + ОбъектРабочий.Наименование + ". Ошибка: " + ОписаниеОшибки());
КонецПопытки;
КонецЕсли;
КонецЕсли;
КонецЦикла;
Сообщить("Обработка завершена. Восстановлено контрагентов: " + КоличествоВосстановленных);
КонецПроцедуры
Использование свойства ОбменДанными.Загрузка = Истина критически важно. Оно блокирует запуск стандартных платформенных проверок конфигурации при записи, предотвращая повторное искажение данных бизнес-логикой и подписками.
Если конфигурации базы-бэкапа и рабочей базы абсолютно идентичны, можно обойтись без написания кода, применив штатный инструмент 1С — обработку ВыгрузкаЗагрузкаДанныхXML.epf (ее можно найти на диске ИТС или в каталогах шаблонов).
Проанализируем этот сценарий детально:
ВыгрузкаЗагрузкаДанныхXML.epf. На вкладке «Выгрузка» отметьте галочкой справочник «Контрагенты» (а также, при необходимости, подчиненные справочники «Договоры контрагентов» и «Банковские счета»). Сделайте выгрузку в XML-файл.После того как данные в центральной базе (ЦБ) приведены в порядок, необходимо решить проблему с периферийными узлами (филиалами), куда ошибочные изменения могли уже уйти или стоят в очереди на отправку. Рассмотрим два сценария действий.
Если администраторы оперативно заблокировали каналы обмена и ошибочные данные не успели загрузиться в базы филиалов, порядок действий следующий:
ОбменДанными.Загрузка = Истина регистрация изменений для обмена не произойдет автоматически.Если обмены отработали и некорректные реквизиты контрагентов уже записались в базы филиалов, ситуация сложнее, но полностью поправима:
Чтобы обезопасить рабочие базы от деструктивного воздействия внешних обработок, придерживайтесь простых правил разработки и администрирования:
.Записать(), ЗаписатьОбъект(), СоздатьЭлемент(). Если это обработка *только для выгрузки*, в ее коде не должно быть методов модификации данных информационной базы-источника.ВыгрузкаЗагрузкаДанныхXML.epf. Она работает в режиме «только чтение» на источнике и гарантированно не вносит никаких изменений при экспорте.