При работе с механизмами обмена данными в системе 1С:Предприятие часто возникает классическая проблема: базы-участники обмена со временем начинают различаться. В одну базу добавили новый реквизит в документ или справочник, а в другой конфигурация осталась прежней. В такой ситуации стандартная выгрузка и загрузка через План обмена может выдавать ошибки, так как принимающая сторона "не знает", что делать с неизвестным ей тегом в XML-файле.
В этой статье мы подробно разберем, как адаптировать обмен данными под изменяющиеся структуры, рассмотрим программные способы игнорирования лишних данных и изучим архитектурные подходы, которые сделают вашу систему обмена более гибкой.
Если вы используете самописную обработку или модифицируете существующий механизм обмена, самый надежный способ избежать ошибок — это отказаться от автоматического чтения объекта функцией ПрочитатьXML() в пользу ручного обхода узлов. Мы можем проанализировать каждый тег в файле перед тем, как пытаться записать его значение в объект базы данных.
Проанализируем пример кода, который позволяет загружать данные, пропуская те реквизиты, которых нет в текущей конфигурации:
// Предположим, мы читаем документ из XML
Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл(ПутьКФайлу);
Пока Чтение.Прочитать() Цикл
Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
ИмяРеквизита = Чтение.Имя;
// Проверяем, существует ли такой реквизит в метаданных текущей базы
МетаданныеОбъекта = Метаданные.Документы.РеализацияТоваровУслуг;
Если МетаданныеОбъекта.Реквизиты.Найти(ИмяРеквизита) <> Неопределено Тогда
// Если реквизит найден, читаем его значение
Значение = СериализаторXDTO.ПрочитатьXML(Чтение);
ОбъектОбмена[ИмяРеквизита] = Значение;
Иначе
// Если реквизита нет, просто пропускаем этот узел
Чтение.Пропустить();
КонецЕсли;
КонецЕсли;
КонецЦикла;
Используя метод Метаданные.Найти() или поиск в коллекции Реквизиты, мы обеспечиваем защиту от "лишних" данных. Если в XML пришел тег "НовыйСверхВажныйРеквизит", которого нет в нашей базе, программа просто пропустит его и перейдет к следующему элементу, не вызывая исключения.
Вместо того чтобы учить базу-приемник игнорировать новые поля, мы можем научить базу-источник не отправлять те данные, которые приемник не сможет переварить. Для этого в модуле Плана обмена существуют специальные предопределенные обработчики.
Рассмотрим использование события ПриОтправкеДанныхПодчиненному. Этот метод вызывается перед тем, как объект будет помещен в сообщение обмена. Здесь мы можем модифицировать передаваемые данные или даже полностью заменить объект.
Процедура ПриОтправкеДанныхПодчиненному(ЭлементДанных, ОтправкаЭлемента)
// Если мы отправляем конкретный тип документа
Если ТипЗнч(ЭлементДанных) = Тип("ДокументОбъект.РеализацияТоваровУслуг") Тогда
// Если мы знаем, что у приемника версия базы ниже,
// мы можем очистить новый реквизит или обнулить его,
// чтобы он не вызывал конфликтов (в зависимости от логики сериализации)
// Либо можно программно сформировать структуру без этого поля.
КонецЕсли;
КонецПроцедуры
Этот подход хорош тем, что он экономит трафик и уменьшает размер XML-файла, так как лишняя информация вообще не попадает в файл обмена.
Современным стандартом обмена в 1С является использование XDTO (XML Data Transfer Objects). В отличие от жесткой привязки к метаданным, XDTO работает через описание схем данных. Это дает колоссальную гибкость:
ЗаписатьXML() мы используем СериализаторXDTO.ЗаписатьДанные(). При чтении через СериализаторXDTO.ПрочитатьДанные() система сопоставляет XML со схемой XDTO, а не напрямую с объектом 1С.Рассмотрим пример чтения через XDTO, который более устойчив к изменениям:
// Чтение данных с использованием типа XDTO
ТипОбъектаXDTO = ФабрикаXDTO.Тип("http://www.my-site.com/exchange", "ДокументПродажа");
ОбъектXDTO = ФабрикаXDTO.ПрочитатьXML(Чтение, ТипОбъектаXDTO);
// Теперь мы можем программно перенести данные из XDTO в объект 1С
// проверяя каждое свойство
Для каждого Свойство Из ОбъектXDTO.Тип().Свойства Цикл
// Логика заполнения...
КонецЦикла;
Если различия между базами становятся существенными, ручное написание кода в обработках становится трудозатратным. В этом случае пора переходить к специализированным инструментам.
Конвертация данных 2.0: Это классический инструмент, где вы создаете "Правила обмена данными" (ПВД). В КД 2 вы можете четко указать, какие реквизиты источника соответствуют реквизитам приемника. Если в источнике есть реквизит, а в приемнике нет — вы просто не создаете правило для этого поля, и проблема решается сама собой.
Конвертация данных 3.0: Работает по принципу "универсального формата" (EnterpriseData). База-источник выгружает данные в промежуточный формат, а база-приемник читает только те данные из этого формата, которые она понимает. Это самый продвинутый способ интеграции, так как он позволяет обновлять конфигурации независимо друг от друга.
Иногда самым простым решением будет не усложнение кода обмена, а приведение структур баз к единому виду. Если в одной базе добавлен важный реквизит, который скоро появится и в других базах, вы можете добавить этот реквизит в "отстающие" базы с помощью Расширения конфигурации.
Преимущества этого метода:
ПрочитатьXML() и ЗаписатьXML() начинают работать автоматически, так как видят реквизит в метаданных (через расширение).Для решения проблемы обмена между разными версиями баз мы рекомендуем следующий алгоритм действий:
ЧтениеXML и проверку через Метаданные.Найти().Попытка...Исключение, чтобы один некорректный объект не останавливал весь процесс обмена данными.Выяснив причину ошибки (несоответствие структуры XML и метаданных), мы можем гибко настроить обмен, сделав его устойчивым к любым изменениям в конфигурациях.