При работе с механизмами версионирования в конфигурации «Управление производственным предприятием» (УПП) разработчики часто сталкиваются с неприятной ситуацией: при попытке восстановить объект из истории изменений система выдает критическую ошибку. Чаще всего это происходит в строке ПрочитатьXML(ЧтениеXML). Проанализируем ситуацию: основная причина кроется в том, что с момента записи версии состав реквизитов объекта в конфигурации изменился — какие-то поля были удалены, переименованы или изменили свой тип данных.
Рассмотрим подробнее, почему стандартные средства платформы 1С пасуют перед этой задачей и как мы можем реализовать «мягкое» восстановление данных, игнорируя несоответствия в метаданных.
Метод ПрочитатьXML предназначен для полной и строгой десериализации объекта. Платформа ожидает, что структура XML-файла идеально соответствует текущему описанию объекта в метаданных конфигурации. Если в XML встречается узел (реквизит), который больше не существует в коде программы, или если структура табличной части претерпела изменения, метод выбрасывает исключение. Игнорировать ошибки внутри этого метода невозможно — это заложено в логику работы платформенного движка.
Для решения этой проблемы нам необходимо отказаться от автоматического чтения и перейти к ручному управлению процессом заполнения данных. Разберем основные стратегии решения.
Вместо того чтобы доверять чтение всей структуры платформе, мы можем самостоятельно перебирать узлы XML-файла и проверять их наличие в текущем объекте. Это самый надежный способ для старых конфигураций типа УПП.
Проанализируем алгоритм реализации:
ЧтениеXML.Посмотрим на пример кода, который реализует такой подход:
Процедура ВосстановитьВерсиюВручную(ДанныеХранилища, СсылкаНаОбъект)
// Получаем двоичные данные из хранилища версии
ДвоичныеДанные = ДанныеХранилища.Получить();
ИмяФайла = ПолучитьИмяВременногоФайла("xml");
ДвоичныеДанные.Записать(ИмяФайла);
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(ИмяФайла);
// Создаем объект для записи
ОбъектДляВосстановления = СсылкаНаОбъект.ПолучитьОбъект();
МетаданныеОбъекта = ОбъектДляВосстановления.Метаданные();
// Читаем до начала данных объекта
Пока ЧтениеXML.Прочитать() Цикл
ТипУзла = ЧтениеXML.ТипУзла;
// Если это начало элемента и это не корневой элемент объекта
Если ТипУзла = ТипУзлаЧтенияXML.НачалоЭлемента Тогда
ИмяУзла = ЧтениеXML.ЛокальноеИмя;
// Проверяем наличие обычного реквизита
РеквизитМетаданных = МетаданныеОбъекта.Реквизиты.Найти(ИмяУзла);
Если РеквизитМетаданных <> Неопределено Тогда
// Считываем значение с учетом типа, определенного в метаданных
ОбъектДляВосстановления[ИмяУзла] = ПрочитатьXML(ЧтениеXML, РеквизитМетаданных.Тип);
ИначеЕсли МетаданныеОбъекта.ТабличныеЧасти.Найти(ИмяУзла) <> Неопределено Тогда
// Здесь должна быть логика обхода строк табличной части
ЗаполнитьТабличнуюЧастьВручную(ОбъектДляВосстановления[ИмяУзла], ЧтениеXML);
Иначе
// Если реквизит не найден, просто пропускаем содержимое узла
ЧтениеXML.Пропустить();
КонецЕсли;
КонецЕсли;
КонецЦикла;
ЧтениеXML.Закрыть();
ОбъектДляВосстановления.Записать();
УдалитьФайлы(ИмяФайла);
КонецПроцедуры
Если структура XML сложная, а ручной перебор через ЧтениеXML кажется слишком громоздким, можно воспользоваться Построителем DOM. Этот метод позволяет загрузить XML в дерево объектов в памяти, что значительно упрощает навигацию.
Рассмотрим преимущества этого подхода: мы можем обращаться к данным по именам тегов и не беспокоиться о порядке следования реквизитов в файле. Если в нашей версии объекта из истории есть лишние данные, мы их просто не вызовем при заполнении текущего объекта 1С.
Пример логики работы с DOM:
ДокументDOM.Реквизиты из метаданных текущего объекта.ПолучитьЭлементыПоИмени().В новых версиях БСП разработчики 1С уже внедрили механизмы, устойчивые к изменению метаданных. Вместо прямого использования ПрочитатьXML, они применяют специализированные обертки. Выясним причину их эффективности: они используют формат FastInfoSet и защищенные процедуры десериализации.
Если в вашей конфигурации есть модули БСП, проверьте наличие функции ВосстановитьОбъектПоXML. Как правило, она обернута в блок Попытка...Исключение, но внутри содержит дополнительную логику сопоставления полей. В случае УПП, где БСП может быть сильно устаревшей, можно позаимствовать код из последних релизов БСП (например, 3.1), где реализован «умный» разбор XML-пакетов.
Самое сложное при ручном восстановлении — это табличные части. Посмотрим на нюансы, которые стоит учесть:
ПрочитатьXML для этой колонки упадет, поэтому используйте проверку Метаданные.ТабличныеЧасти.ИмяТЧ.Атрибуты.Найти(ИмяКолонки).Попытка.Дата, Номер, ПометкаУдаления. В XML они могут располагаться отдельно от пользовательских реквизитов.Таким образом, для стабильной работы восстановления в условиях меняющейся конфигурации, отказ от стандартного ПрочитатьXML в пользу ручного перебора узлов или использования DOM-модели является единственным надежным решением. Это позволит вашей системе сохранять живучесть даже после масштабных обновлений и рефакторинга метаданных.