Как передать и получить таблицу значений через COM-соединение с помощью сериализации

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

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

Рассмотрим причину возникновения ошибок при прямой передаче объектов и проанализируем основные способы получения таблицы значений в исходном виде.

Причина ошибки при передаче COM-объекта в методы сериализации

Разберем ситуацию, с которой часто сталкиваются разработчики. При попытке передать таблицу значений, созданную во внешней базе, напрямую в методы локальной базы (например, в СериализаторXDTO.ЗаписатьXML или ОбщегоНазначения.ЗначениеВСтрокуXML) возникает ошибка «Несоответствие типов» или «Ошибка отображения типов».

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

Способ 1. Использование функций ЗначениеВСтрокуВнутр и ЗначениеИзСтрокиВнутр

Самый простой и быстрый способ передачи таблицы значений с примитивными типами данных — использование внутренней строки 1С. Метод ЗначениеВСтрокуВнутр вызывается через объект соединения, а восстановление структуры выполняется локальным методом ЗначениеИзСтрокиВнутр.

Рассмотрим пример кода на стороне базы-приемника:


// 1. Устанавливаем COM-соединение
Соединение = Соединение82_.Connect(СтрокаПодключения);

// 2. Формируем или получаем таблицу во внешней базе
// Все действия с объектом ТаблицаНовая выполняются в контексте внешней базы
ТаблицаCOM = Соединение.NewObject("ТаблицаЗначений");
ТаблицаCOM.Колонки.Добавить("IDDoc", Соединение.NewObject("ОписаниеТипов", "Строка"));
ТаблицаCOM.Колонки.Добавить("Сумма", Соединение.NewObject("ОписаниеТипов", "Число"));

НоваяСтрока = ТаблицаCOM.Добавить();
НоваяСтрока.IDDoc = "DOC-0001";
НоваяСтрока.Сумма = 15000;

// 3. Сериализуем таблицу во внутреннюю строку на стороне COM-базы
СтрокаДанных = Соединение.ЗначениеВСтрокуВнутр(ТаблицаCOM);

// 4. Восстанавливаем таблицу значений в текущей базе
ТаблицаРезультат = ЗначениеИзСтрокиВнутр(СтрокаДанных);

Обратите внимание: данный метод подходит только тогда, когда колонки таблицы содержат примитивные типы данных (Строка, Число, Дата, Булево). Если в колонках содержатся ссылки на объекты базы (например, СправочникСсылка), при десериализации вы получите «битые» ссылки, так как УИД объектов в разных базах могут не совпадать.

Способ 2. Упаковка в ХранилищеЗначения и передача через XML

Если требуется уменьшить объем передаваемых данных или упаковать таблицу в стандартный XML-формат, можно поместить таблицу значений в ХранилищеЗначения внутри COM-соединения, а затем получить его строковое представление с помощью метода XMLСтрока.

Проанализируем пошаговый алгоритм выполнения этой операции:

  1. Создаем таблицу значений во внешней базе через COM-объект.
  2. Помещаем созданную таблицу в объект ХранилищеЗначения во внешней базе.
  3. Преобразуем хранилище значений в строку XML с помощью функции XMLСтрока.
  4. Передаем полученную строку в текущую базу и считываем ее функцией XMLЗначение, разворачивая хранилище.

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


// Создание и заполнение таблицы во внешней базе
ТаблицаCOM = Соединение82.NewObject("ТаблицаЗначений");
// (Заполнение колонок и строк...)

// Создаем ХранилищеЗначения в контексте COM-базы
ХранилищеCOM = Соединение82.NewObject("ХранилищеЗначения", ТаблицаCOM);

// Получаем XML-строку от хранилища
СериализованнаяСтрока = Соединение82.XMLСтрока(ХранилищеCOM);

// В текущей базе восстанавливаем ХранилищеЗначения и получаем из него таблицу
ХранилищеЛокальное = XMLЗначение(Тип("ХранилищеЗначения"), СериализованнаяСтрока);
ТаблицаЛокальная = ХранилищеЛокальное.Получить();

Способ 3. Сериализация данных через XDTO

Для универсальной работы с XML-структурами можно использовать механизм сериализации XDTO. В этом случае функции сериализации и чтения XML оформляются на стороне каждой из баз.

Пример функций сериализации и десериализации данных:


&НаСервереБезКонтекста
Функция СериализоватьДанные(Объект)
    
    ХДТО = СериализаторXDTO.ЗаписатьXDTO(Объект);
    ЗаписьXML = Новый ЗаписьXML;
    ЗаписьXML.УстановитьСтроку();
    
    ФабрикаXDTO.ЗаписатьXML(ЗаписьXML, ХДТО);
    Возврат ЗаписьXML.Закрыть();
    
КонецФункции

&НаСервереБезКонтекста
Функция ДесериализоватьДанные(СтрокаXML)
    
    ЧтениеXML = Новый ЧтениеXML;
    ЧтениеXML.УстановитьСтроку(СтрокаXML);
    Данные = СериализаторXDTO.ПрочитатьXML(ЧтениеXML);
    ЧтениеXML.Закрыть();
    
    Возврат Данные;
    
КонецФункции

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

Важные правила работы с COM-соединением

← На главную