Как решить проблему с ошибкой «Несоответствие типов» при выгрузке по узлу обмена в Конвертации данных 2.0 для ПВД с произвольным алгоритмом?

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

При организации регулярного обмена данными между конфигурациями 1С часто возникает необходимость передавать специфические пакеты информации. Типичный сценарий: выгрузка данных из регистров накопления или сведений конфигурации-источника (например, 1С:Управление торговлей 11) и их сворачивание в один виртуальный документ-регистратор в базе-приемнике. Самого этого документа в источнике физически не существует — он генерируется «на лету» с помощью произвольного алгоритма в правилах выгрузки данных (ПВД).

Такой механизм прекрасно работает при интерактивной выгрузке через обработку Универсальный обмен данными XML. Однако при попытке настроить автоматический регулярный обмен с указанием конкретного Узла плана обмена система выдает критическую ошибку:

Ошибка при вызове метода контекста (НайтиПоТипу): Несоответствие типов (параметр номер '1')

В этой статье мы подробно разберем, почему возникает данная проблема, проанализируем внутренние механизмы работы Конвертации данных 2.0 (2.1) и рассмотрим три надежных способа её решения.

Выясняем причину возникновения ошибки

Давайте разберем поведение платформы и обработок обмена по шагам. Когда в настройках выгрузки не указан узел обмена, система последовательно выполняет все ПВД. Но как только мы позиционируемся на конкретном узле плана обмена, логика работы кардинально меняется:

  1. Система переходит в режим инкрементальной выгрузки (выгружаются только измененные данные).
  2. Для оптимизации процесса выгрузки обработка пытается составить карту соответствия правил и физических объектов метаданных, для которых зарегистрированы изменения.
  3. В цикле обхода правил выгрузки система пытается определить тип источника для каждого ПВД, используя системную функцию Метаданные.НайтиПоТипу().
  4. В качестве параметра передается свойство СтрокаПравилаВыгрузки.ОбъектВыборки.
  5. Поскольку наше ПВД настроено на «Произвольный алгоритм», а самого документа-источника в базе нет, поле «Объект выборки» в правилах остается пустым (значение Неопределено).

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

Ниже детально рассмотрим три практических способа обхода этого системного ограничения.


Способ 1. Перенос логики в глобальный обработчик конвертации (Рекомендуемый)

Самый чистый с архитектурной точки зрения метод — полностью отказаться от использования проблемного ПВД. Так как у нас нет реального объекта-источника, мы можем инициировать программную выгрузку данных напрямую из глобальных событий конвертации, которые выполняются один раз за сеанс обмена.

Выполним следующие шаги для реализации этого метода:

  1. Откроем правила обмена в конфигурации Конвертация данных 2.0.
  2. Удалим (или деактивируем) проблемное ПВД для виртуального документа.
  3. Перейдем на вкладку «Алгоритмы/Запросы» или откроем настройки самой конвертации на вкладке «Глобальные обработчики».
  4. Найдем обработчик «Перед выгрузкой данных». Этот обработчик выполняется в самом начале процесса, когда дерево метаданных уже прочитано, но выгрузка объектов еще не началась.
  5. Напишем здесь алгоритм выборки данных из регистров и программного вызова выгрузки по правилу конвертации объектов (ПКО).

Пример программного кода для обработчика «Перед выгрузкой данных»:


// Запрос для выборки данных из регистров-источников
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Продажи.Номенклатура КАК Номенклатура,
    |	Продажи.Количество КАК Количество,
    |	Продажи.Сумма КАК Сумма
    |ИЗ
    |	РегистрНакопления.ВыручкаИСебестоимостьПродаж КАК Продажи
    |ГДЕ
    |	Продажи.Период МЕЖДУ &НачалоПериода И &КонецПериода";

Запрос.УстановитьПараметр("НачалоПериода", НачалоПериода);
Запрос.УстановитьПараметр("КонецПериода", КонецПериода);

РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
    
    // Формируем структуру данных, которую ожидает наше ПКО приемника
    СтруктураДанных = Новый Структура;
    СтруктураДанных.Вставить("ТабличнаяЧастьДокумента", РезультатЗапроса.Выгрузить());
    СтруктураДанных.Вставить("Дата", ТекущаяДата());
    СтруктураДанных.Вставить("Комментарий", "Сгенерировано автоматически по данным регистров");
    
    // Вызываем выгрузку по конкретному правилу конвертации объектов (ПКО)
    // Имя ПКО должно точно совпадать с именем правила для документа-приемника
    ВыгрузитьПоПравилу(СтруктураДанных, , , , "ИмяВашегоПКО_ДокументРегистратор");
    
КонецЕсли;

Преимущество этого метода заключается в том, что система не будет спотыкаться на пустом объекте выборки в правилах выгрузки, так как самого ПВД больше не существует в структуре обмена.


Способ 2. Использование фиктивного «Объекта выборки» в ПВД

Если вам критически важно сохранить логику именно внутри ПВД (например, для наглядности структуры правил конвертации), можно применить обходной маневр и «обмануть» валидатор метаданных платформы.

Разберем этот процесс по шагам:

  1. В настройках ПВД в поле «Объект выборки» укажем любой реально существующий в базе-источнике объект метаданных. Лучше всего выбрать объект, который гарантированно присутствует в любой базе и содержит минимальное количество записей (например, справочник Организации или константу ВалютаРегламентированногоУчета).
  2. Теперь при выгрузке по узлу метод Метаданные.НайтиПоТипу() отработает корректно и вернет тип выбранного фиктивного объекта. Ошибка несоответствия типов исчезнет.
  3. Чтобы предотвратить реальную выгрузку этого фиктивного объекта, перейдем в обработчик ПВД «Перед обработкой» и напишем там наш произвольный алгоритм, завершив его принудительным отказом от стандартной выборки.

Пример кода в обработчике ПВД «Перед обработкой»:


// Выполняем наш произвольный алгоритм формирования данных
ТаблицаДанных = ПолучитьДанныеДляВиртуальногоДокумента();

Для Каждого СтрокаДанных Из ТаблицаДанных Цикл
    // Выгружаем данные через ПКО
    ВыгрузитьПоПравилу(СтрокаДанных, , , , "ИмяВашегоПКО_ДокументРегистратор");
КонецЦикла;

// Говорим системе, что стандартный выбор объектов (например, Организаций) делать не нужно
Отказ = Истина;

Важное предупреждение: При обмене по узлу плана обмена правила выгрузки запускаются только тогда, когда для указанного объекта выборки зарегистрированы изменения на узле. Если вы указали в качестве объекта выборки справочник Организации, вам придется программно регистрировать фиктивное изменение для этого справочника при каждом обмене, иначе система решит, что изменений нет, и просто пропустит это ПВД.


Способ 3. Модификация кода обработки «УниверсальныйОбменДаннымиXML»

Если вы используете внешнюю обработку выгрузки (например, запускаете обмен по расписанию через командную строку или регламентное задание с внешней обработкой УниверсальныйОбменДаннымиXML.epf), вы можете устранить ошибку непосредственно в коде самой обработки.

Давайте проанализируем, где именно происходит сбой, и внесем исправления:

  1. Откроем обработку УниверсальныйОбменДаннымиXML в конфигураторе.
  2. Найдем процедуру или функцию с именем ВыполнитьВыгрузкуИзмененныхДанныхДляУзлаОбмена.
  3. Найдем цикл обхода правил выгрузки, в котором вызывается метод НайтиПоТипу.
  4. Добавим проверку на заполненность типа объекта выборки перед вызовом метода.

Отредактируем код следующим образом:


Для Каждого СтрокаПравилаВыгрузки Из ВременныйМассивПравилКонвертации Цикл
    
    // БЫЛО:
    // МетаданныеПВД = Метаданные.НайтиПоТипу(СтрокаПравилаВыгрузки.ОбъектВыборки);
    // МассивВыгружаемыхМетаданных.Добавить(МетаданныеПВД);
    
    // СТАЛО:
    // Добавляем проверку, чтобы избежать падения при пустом объекте выборки (произвольный алгоритм)
    Если ЗначениеЗаполнено(СтрокаПравилаВыгрузки.ОбъектВыборки) Тогда
        МетаданныеПВД = Метаданные.НайтиПоТипу(СтрокаПравилаВыгрузки.ОбъектВыборки);
        Если МетаданныеПВД <> Неопределено Тогда
            МассивВыгружаемыхМетаданных.Добавить(МетаданныеПВД);
        КонецЕсли;
    КонецЕсли;
    
КонецЦикла;

После этого изменения обработка будет полностью игнорировать пустые объекты выборки в ПВД при анализе изменений на узле обмена, и выгрузка произвольным алгоритмом отработает в штатном режиме.


Организация инкрементальной выгрузки для виртуального документа

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

Для этого в произвольном запросе (в первом или втором способе) следует обращаться не к физическим таблицам регистров, а к таблицам зарегистрированных изменений этих регистров на узле обмена.

Проанализируем пример запроса для получения изменений регистра накопления:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ИзмененияРегистра.Регистратор КАК Регистратор,
    |	ИзмененияРегистра.НомерСтроки КАК НомерСтроки
    |ИЗ
    |	РегистрНакопления.ВыручкаИСебестоимостьПродаж.Изменения КАК ИзмененияРегистра
    |ГДЕ
    |	ИзмененияРегистра.Узел = &УзелОбмена";

// Ссылка на узел обмена в обработчиках КД обычно доступна через переменную "УзелДляОбмена"
Запрос.УстановитьПараметр("УзелОбмена", УзелДляОбмена);

РезультатЗапроса = Запрос.Выполнить();

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

Для очистки регистрации используем следующий метод в конце вашего алгоритма выгрузки:


// Очищаем регистрацию изменений по регистру для нашего узла
ПланыОбмена.УдалитьРегистрациюИзменений(УзелДляОбмена, Метаданные.РегистрыНакопления.ВыручкаИСебестоимостьПродаж);

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

← На главную