При организации обмена данными между базами 1С через JSON часто используется стандартный механизм сериализации объектов, например, наборов записей регистров. Однако этот подход имеет свою специфику: он чувствителен к порядку полей (измерений, реквизитов, ресурсов) в метаданных. Если в одной из баз этот порядок изменится, при загрузке данных возникнет ошибка "Ошибка преобразования данных XDTO". Давайте разберемся, почему так происходит и как решить эту проблему.
Проанализируем ситуацию. Выгрузка данных выполняется с помощью СериализаторXDTO.ЗаписатьJSON(), а загрузка — через ПрочитатьJSON(). Проблема кроется в том, как 1С формирует JSON при сериализации объектов базы данных. В итоговый файл добавляется специальное свойство "#type", которое явно указывает тип данных, например, "InformationRegisterRecordSet.ИмяВашегоРегистра". При чтении такого JSON платформа 1С видит этот тип и пытается сразу создать соответствующий объект, строго сопоставляя поля по их порядку в метаданных, а не по именам. Если порядок нарушен — происходит сбой.
Рассмотрим несколько способов решения этой задачи, от самых простых и быстрых до более надежных и архитектурно правильных.
Если у вас есть доступ к конфигурациям обеих баз, самым быстрым решением будет устранить первопричину — расхождение в структурах.
Изменение порядка в метаданных. Откройте конфигуратор базы-приемника, найдите нужный регистр сведений и на закладке "Данные" с помощью стрелок переместите измерения так, чтобы их порядок полностью совпадал с порядком в базе-источнике. После обновления конфигурации базы данных загрузка должна заработать. Это самый прямой и правильный способ, если изменение метаданных допустимо.
Формирование данных в нужном порядке при выгрузке. Если менять метаданные в приемнике нельзя, можно "подстроиться" под них на стороне источника. Вместо прямой выгрузки набора записей, сначала получите данные запросом, перечислив поля в том порядке, в котором они ожидаются в базе-приемнике. Затем результат запроса выгрузите в таблицу значений и уже ее загрузите в набор записей для последующей сериализации.
// Пример на стороне источника
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| МойРегистр.Измерение2, // Ставим в том порядке, как в базе-приемнике
| МойРегистр.Измерение1,
| МойРегистр.Ресурс1
|ИЗ
| РегистрСведений.МойРегистр КАК МойРегистр";
ТаблицаДляВыгрузки = Запрос.Выполнить().Выгрузить();
НаборЗаписей = РегистрыСведений.МойРегистр.СоздатьНаборЗаписей();
НаборЗаписей.Загрузить(ТаблицаДляВыгрузки);
// Далее идет ваша стандартная процедура сериализации НабораЗаписей в JSON
Этот способ не требует изменения конфигураций и логики выгрузки. Вся магия происходит в базе-приемнике непосредственно перед чтением файла. Идея в том, чтобы программно изменить текстовое содержимое JSON-строки.
Ключевой трюк — убрать информацию о типе. Как мы выяснили, проблема в свойстве "#type". Если его удалить, то 1С при чтении функцией ПрочитатьJSON() не будет пытаться создать строго типизированный объект базы данных. Вместо этого она создаст универсальную коллекцию — Структуру или Соответствие с вложенным Массивом структур. А с такой коллекцией уже можно работать гибко, сопоставляя поля по именам.
Посмотрим на пример:
// Получаем текст из файла JSON
ТекстJSON = ПолучитьТекстИзФайла(ПутьКФайлу);
// С помощью простой замены удаляем информацию о типе набора записей
// Имя регистра нужно подставить свое
ТекстJSON = СтрЗаменить(ТекстJSON, """", "#type"": ""InformationRegisterRecordSet.ИмяВашегоРегистра""");
// Также нужно удалить типы для каждой отдельной записи
ТекстJSON = СтрЗаменить(ТекстJSON, """", "#type"": ""InformationRegisterRecordManager.ИмяВашегоРегистра""");
// Теперь читаем "обезличенный" JSON
ПараметрыЧтенияJSON = Новый ПараметрыЧтенияJSON(,,Истина); // Истина - чтобы имена свойств были в формате CamelCase
ДанныеКакСтруктура = ПрочитатьJSON(ТекстJSON, ПараметрыЧтенияJSON);
// ДанныеКакСтруктура будет содержать массив записей, который можно обойти
НаборЗаписей = РегистрыСведений.ИмяВашегоРегистра.СоздатьНаборЗаписей();
// Устанавливаем отборы, если они есть в JSON
// ...
Для Каждого ЭлементМассива Из ДанныеКакСтруктура.value Цикл
НоваяЗапись = НаборЗаписей.Добавить();
// Теперь заполняем по именам, а не по порядку!
ЗаполнитьЗначенияСвойств(НоваяЗапись, ЭлементМассива);
КонецЦикла;
НаборЗаписей.Записать();
Важный момент: использование регулярных выражений, как предлагали на форуме, — более мощный, но и более сложный вариант. Для простой задачи удаления строки с типом обычно достаточно функции СтрЗаменить(). Регулярные выражения могут понадобиться, если нужно не просто удалить тип, а переставить сами свойства местами в строке, что является гораздо более хрупким решением.
Этот способ требует доработки механизма обмена, но делает его гораздо более устойчивым к изменениям метаданных в будущем. Он считается лучшей практикой для обмена табличными данными.
Алгоритм следующий:
На стороне источника: Данные из регистра выгружаются не в НаборЗаписей, а сразу в ТаблицуЗначений.
Эта ТаблицаЗначений сериализуется в JSON. Платформа 1С отлично умеет это делать, и результат не будет содержать жесткой привязки к объекту регистра.
На стороне приемника: JSON-строка десериализуется обратно в ТаблицуЗначений.
Создается пустой НаборЗаписей, и в него загружаются данные из полученной таблицы методом Загрузить(). Этот метод автоматически сопоставляет колонки таблицы с измерениями и ресурсами набора записей по их именам. Порядок колонок в таблице уже не имеет значения.
Этот подход решает проблему в корне, так как вся логика сопоставления по именам перекладывается на платформу, которая делает это эффективно и правильно.
Также в качестве альтернативы JSON можно рассмотреть встроенный механизм сериализации через ЗначениеВСтрокуВнутр() и ЗначениеИзСтрокиВнутр(). Он также работает с ТаблицейЗначений и не зависит от порядка колонок, но создает нечитаемый для человека формат данных.
Итак, столкнувшись с ошибкой преобразования XDTO из-за разного порядка полей, у вас есть несколько вариантов действий:
ТаблицыЗначений в качестве промежуточного формата. Это сделает ваш механизм обмена гибким и устойчивым к будущим изменениям (Способ 3).Выбор конкретного способа зависит от ваших прав, сроков и желания построить надежную систему.