Как исправить ошибку «Несоответствие типов XDTO: Тип не соответствует типу» при работе с Диадок и ФНС

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При работе с электронным документооборотом (ЭДО), особенно в интеграционных решениях с системой Диадок, разработчики часто сталкиваются с крайне странной ошибкой: Несоответствие типов XDTO: Тип '{URI}ИмяТипа' не соответствует типу '{URI}ИмяТипа'. На первый взгляд сообщение кажется абсурдным, ведь платформа утверждает, что тип не соответствует самому себе. Однако в мире 1С и XDTO за этим скрывается глубокая логика работы с фабриками и пространствами имен.

В этой статье мы подробно разберем, почему возникает эта ошибка, как проанализировать контекст выполнения кода и какие способы решения существуют для исправления этой ситуации в конфигурациях 1С.

Разберем причину возникновения ошибки

Основная причина, по которой 1С выдает ошибку «Тип А не соответствует типу А», заключается в том, что платформа сравнивает не только строковое имя типа и его URI (пространство имен), но и саму Фабрику XDTO, в контексте которой был создан объект. В оперативной памяти 1С может одновременно существовать несколько фабрик, содержащих идентичные наборы схем (например, схемы ФНС для счетов-фактур ON_NSCHFDOPPR).

Проанализируем типичную ситуацию: у вас есть корневой объект (например, УПД), который был создан внешней библиотекой или загружен из файла с использованием локальной фабрики. Затем вы пытаетесь программно создать дочерний объект (например, ТекстИнфТип) через глобальную фабрику ФабрикаXDTO или другую фабрику, созданную вручную. Несмотря на то, что описания типов в этих фабриках идентичны, для платформы это разные объекты метаданных. Попытка вставить объект из одной фабрики в свойство объекта из другой фабрики неминуемо приведет к исключению.

Анализ кода и поиск узких мест

Рассмотрим фрагмент кода, который часто становится источником проблем при копировании из типовых обработок:


// Ошибка часто возникает здесь
ТекстИнф = Фабрика.Создать(Фабрика.Тип(ИмяПакетаXDTO, "ТекстИнфТип"));
ТекстИнф.Значен = InfoFileId;
ТекстИнф.Идентиф = "ID";
Попытка
    ИнфПолФХЖ1.ТекстИнф.Добавить(ТекстИнф); // Ошибка: Несоответствие типов
Исключение
    // Обработка ошибки
КонецПопытки;

В данном примере переменная Фабрика может указывать на глобальную фабрику конфигурации, в то время как объект ИнфПолФХЖ1 был порожден от другой фабрики, инициализированной внутри модуля Диадока (так называемые «матрешки» в коде интеграции). Выясним, как сделать код универсальным и устойчивым к смене контекста.

Решение №1: Создание объекта напрямую через список

Самый надежный способ избежать конфликта фабрик — это не создавать объект отдельно, а позволить коллекции родительского объекта самой породить нужный элемент. Если свойство является списковым (максимальное количество появлений больше 1), метод Добавить() у объекта СписокXDTO умеет создавать пустой объект правильного типа в контексте «своей» фабрики.

Проанализируем исправленный код:


// Вместо создания через внешнюю фабрику, используем метод Добавить()
НовыйТекстИнф = ИнфПолФХЖ1.ТекстИнф.Добавить(); 
// Теперь НовыйТекстИнф ГАРАНТИРОВАННО имеет тот же тип, что и коллекция
НовыйТекстИнф.Значен = InfoFileId;
НовыйТекстИнф.Идентиф = "ID";

Этот подход исключает необходимость указывать URI пространства имен или искать нужную фабрику вручную. Платформа сама определит тип на основе метаданных свойства ТекстИнф.

Решение №2: Получение типа из метаданных свойства

Если вам необходимо сначала заполнить объект, а только потом добавить его в коллекцию (или если свойство не является списковым), рекомендуется получать тип непосредственно из родительского объекта. Рассмотрим, как это сделать программно:


// Получаем определение свойства из родительского объекта
СвойствоТекстИнф = ИнфПолФХЖ1.Свойства().Получить("ТекстИнф");
// Получаем точный тип, который ожидает это свойство
ТипОбъекта = СвойствоТекстИнф.Тип;

// Создаем объект через фабрику, которой принадлежит этот тип
НовыйОбъект = Фабрика.Создать(ТипОбъекта); 
НовыйОбъект.Значен = InfoFileId;

// Теперь добавление пройдет без ошибок
ИнфПолФХЖ1.ТекстИнф.Добавить(НовыйОбъект);

Важный момент: Обратите внимание, что в методе Фабрика.Создать() мы передаем именно объект типа ТипXDTO, полученный из метаданных, а не строковое имя. Это гарантирует совпадение контекста фабрики.

Особенности работы с интеграцией Диадок

В сообщениях форума упоминалось, что код Диадока представляет собой сложную структуру («матрешки»). Это связано с тем, что разработчики Диадока часто используют динамическую загрузку схем XSD из макетов обработки.

Выясним, почему «тупой копипаст» не всегда работает:

  1. Разные версии схем: В конфигурации может быть загружен пакет для версии 5.01, а обработка Диадока может работать с версией 5.02. Имена типов будут одинаковыми, но пространства имен (URI) — разными.
  2. Локальные фабрики: Интеграционные модули часто создают локальную фабрику через СоздатьФабрикуXDTO(МассивПутейКФайламXSD). Объекты этой фабрики несовместимы с объектами глобальной фабрики 1С.
  3. Контекст выполнения: Если код выполняется на стороне сервера в одном модуле, а фабрика инициализирована в другом, передача объектов XDTO между ними может приводить к неожиданным результатам, если не соблюдена чистота типов.

Практические советы по отладке

Если вы столкнулись с этой ошибкой, выполните следующие действия в отладчике:

  1. Найдите место, где происходит вызов Добавить() или присваивание свойства.
  2. В окне «Вычислить выражение» проверьте тип создаваемого объекта: ВашОбъект.Тип().ПространствоИмен.
  3. Затем проверьте ожидаемый тип в свойстве родителя: Родитель.Свойства().Получить("ИмяСвойства").Тип.ПространствоИмен.
  4. Сравните эти строки. Даже если они совпадают, проверьте сами объекты типов. Если идентификаторы типов в памяти (внутренние ID 1С) различаются, значит, они принадлежат разным фабрикам.

Используя приведенные выше методы (создание через Добавить() или получение типа через родительское свойство), вы сделаете свой код устойчивым к изменениям в структуре пакетов XDTO и особенностям реализации внешних интеграционных модулей. Помните, что в XDTO важна не только структура данных, но и строгое соответствие метаданных контексту их создания.

← На главную