Как передать таблицу значений через COM-соединение в 1С?

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

При интеграции двух информационных баз 1С с помощью технологии COM-соединения разработчики часто сталкиваются с задачей быстрой загрузки данных в табличную часть документа или набор записей регистра. Типичный сценарий — выполнить запрос в текущей базе и загрузить полученную таблицу значений напрямую в объект внешней базы через метод Загрузить().

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


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

При выполнении этой конструкции платформа выдает исключение: «Несоответствие типов (параметр номер '1')» именно на строке вызова метода Загрузить(). Выясним причину этой ошибки и подробно разберем рабочие способы передачи табличных данных.

Почему возникает ошибка несоответствия типов?

Проанализируем механику работы COM-соединения на уровне платформы 1С. Метод набора записей или табличной части Загрузить() ожидает на вход внутренний объект типа ТаблицаЗначений, созданный строго в адресном пространстве целевой базы.

Когда мы передаем таблицу значений из текущей базы во внешнюю через COM-интерфейс, платформа на принимающей стороне получает не нативный объект ТаблицаЗначений, а универсальную внешнюю COM-обертку (интерфейс IDispatch). Внешняя база не может определить ее как свою собственную таблицу значений, что и приводит к ошибке типизации.

Кроме того, если таблица содержит ссылочные типы данных (например, справочники Номенклатура или Контрагенты), ссылки текущей базы не имеют прямого смысла для внешней базы, если только базы не синхронизированы по уникальным идентификаторам (GUID).

Разберем основные практические способы обхода этой проблемы.

Способ 1. Сериализация таблицы через СериализаторXDTO (рекомендуемый)

Рассмотрим наиболее универсальный и надежный вариант — использование механизма XDTO. Платформа 1С умеет сериализовать таблицу значений в формат XML и корректно восстанавливать ее на стороне COM-соединения.

Разберем по шагам, как это реализовать:

  1. Выгружаем данные запроса в таблицу значений текущей базы.
  2. Сериализуем полученную таблицу в XML-строку с помощью объекта СериализаторXDTO.
  3. Во внешней базе через COM-соединение создаем объект ЧтениеXML и передаем в него полученную строку.
  4. С помощью СериализаторXDTO внешней базы десериализуем данные обратно в «родную» для нее таблицу значений.

Посмотрим на пример реализации в коде:


ТЗ_Источник = Запрос.Выполнить().Выгрузить();

// 1. Сериализуем таблицу в XML-строку в текущей базе
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();
СериализаторXDTO.ЗаписатьXML(ЗаписьXML, ТЗ_Источник);
СтрокаXML = ЗаписьXML.Закрыть();

// 2. Восстанавливаем таблицу в контексте внешней базы
ЧтениеXML = Коннект.NewObject("ЧтениеXML");
ЧтениеXML.УстановитьСтроку(СтрокаXML);
ТЗ_Приемник = Коннект.СериализаторXDTO.ПрочитатьXML(ЧтениеXML);

// 3. Загружаем готовую внутреннюю таблицу в движения
Док.Движения.Продажи.Загрузить(ТЗ_Приемник);
Док.Движения.Продажи.Записать();

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

Способ 2. Создание таблицы значений непосредственно в COM-контексте

Если мы хотим избежать строковой сериализации или требуется трансформировать данные на лету, таблицу значений можно создать прямо во внешнем контексте через метод NewObject().

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


ТЗ_Источник = Запрос.Выполнить().Выгрузить();

// Создаем пустую таблицу значений во внешней базе
ТЗ_Приемник = Коннект.NewObject("ТаблицаЗначений");

// Создаем колонки во внешней таблице
Для Каждого Колонка Из ТЗ_Источник.Колонки Цикл
    ТЗ_Приемник.Колонки.Добавить(Колонка.Имя);
КонецЦикла;

// Заполняем строки данными
Для Каждого СтрИсточника Из ТЗ_Источник Цикл
    СтрПриемника = ТЗ_Приемник.Добавить();
    Для Каждого Колонка Из ТЗ_Источник.Колонки Цикл
        // Передаем примитивные значения или сопоставленные ссылки
        СтрПриемника[Колонка.Имя] = СтрИсточника[Колонка.Имя];
    КонецЦикла;
КонецЦикла;

// Теперь таблица полностью принадлежит внешнему контексту
Док.Движения.Продажи.Загрузить(ТЗ_Приемник);
Док.Движения.Продажи.Записать();

Следует учитывать, что при больших объемах данных (десятки тысяч строк) построчный обход через COM-соединение работает медленно из-за большого количества межпроцессных вызовов.

Способ 3. Передача через функции внутреннего формата или временный файл

Для простых структур данных или таблиц, содержащих примитивные типы, можно использовать встроенные функции сериализации внутреннего формата 1С:


СтрокаДанных = ЗначениеВСтрокуВнутр(ТЗ_Источник);
ТЗ_Приемник = Коннект.ЗначениеИзСтрокиВнутр(СтрокаДанных);
Док.Движения.Продажи.Загрузить(ТЗ_Приемник);

Однако при работе с очень большими таблицами (от десятков тысяч строк) работа с гигантскими строками в оперативной памяти может вызывать ошибку Ошибка преобразования: bad allocation. В этом случае надежнее использовать промежуточную выгрузку на диск через ЗначениеВФайл и ЗначениеИзФайла:


ИмяФайла = ПолучитьИмяВременногоФайла("dat");
ЗначениеВФайл(ИмяФайла, ТЗ_Источник);

// Читаем файл в контексте внешнего соединения
ТЗ_Приемник = Коннект.ЗначениеИзФайла(ИмяФайла);
Док.Движения.Продажи.Загрузить(ТЗ_Приемник);

УдалитьФайлы(ИмяФайла);

Обратите внимание: чтобы данный подход сработал, файл должен быть доступен по общему сетевому пути как серверу источника, так и серверу приемника, если они расположены на разных физических машинах.

Подводные камни при работе с COM

При организации обмена через COM-соединение важно помнить о технических ограничениях:

  1. Преобразование чисел: при прямой передаче числовых данных через вызовы COM-интерфейса числа преобразуются в тип Double, что может приводить к погрешностям округления в копейках. Использование сериализации через XML или JSON решает эту проблему.
  2. Освобождение памяти: COM-объекты удерживаются в оперативной памяти до явного закрытия соединения. После окончания всех операций обязательно очищайте переменную подключения: Коннект = Неопределено;.
  3. Разрядность платформ: соединение между 32-битным и 64-битным процессами требует настройки COM+ приложения (dllhost) в операционной системе. На серверах под управлением Linux технология COM-соединения не поддерживается, и в таких сценариях следует переходить на HTTP-сервисы.
← На главную