При интеграции двух информационных баз 1С с использованием COM-соединения часто возникает необходимость передать таблицу значений из одной базы в другую. Прямой обход строк таблицы через COM-объект в цикле работает крайне медленно из-за постоянных сетевых вызовов между процессами. Чтобы оптимизировать передачу данных, используют сериализацию — приведение таблицы к строковому виду на стороне внешней базы и последующую десериализацию в текущей базе.
Рассмотрим причину возникновения ошибок при прямой передаче объектов и проанализируем основные способы получения таблицы значений в исходном виде.
Разберем ситуацию, с которой часто сталкиваются разработчики. При попытке передать таблицу значений, созданную во внешней базе, напрямую в методы локальной базы (например, в СериализаторXDTO.ЗаписатьXML или ОбщегоНазначения.ЗначениеВСтрокуXML) возникает ошибка «Несоответствие типов» или «Ошибка отображения типов».
Это происходит потому, что объект ТаблицаЗначений, сформированный в контексте COM-соединения, для текущей базы является типом COMОбъект. Локальные функции 1С не могут обработать его напрямую. Сериализацию необходимо выполнять полностью внутри COM-контекста, передавая между базами только примитивный тип — строку.
Самый простой и быстрый способ передачи таблицы значений с примитивными типами данных — использование внутренней строки 1С. Метод ЗначениеВСтрокуВнутр вызывается через объект соединения, а восстановление структуры выполняется локальным методом ЗначениеИзСтрокиВнутр.
Рассмотрим пример кода на стороне базы-приемника:
// 1. Устанавливаем COM-соединение
Соединение = Соединение82_.Connect(СтрокаПодключения);
// 2. Формируем или получаем таблицу во внешней базе
// Все действия с объектом ТаблицаНовая выполняются в контексте внешней базы
ТаблицаCOM = Соединение.NewObject("ТаблицаЗначений");
ТаблицаCOM.Колонки.Добавить("IDDoc", Соединение.NewObject("ОписаниеТипов", "Строка"));
ТаблицаCOM.Колонки.Добавить("Сумма", Соединение.NewObject("ОписаниеТипов", "Число"));
НоваяСтрока = ТаблицаCOM.Добавить();
НоваяСтрока.IDDoc = "DOC-0001";
НоваяСтрока.Сумма = 15000;
// 3. Сериализуем таблицу во внутреннюю строку на стороне COM-базы
СтрокаДанных = Соединение.ЗначениеВСтрокуВнутр(ТаблицаCOM);
// 4. Восстанавливаем таблицу значений в текущей базе
ТаблицаРезультат = ЗначениеИзСтрокиВнутр(СтрокаДанных);
Обратите внимание: данный метод подходит только тогда, когда колонки таблицы содержат примитивные типы данных (Строка, Число, Дата, Булево). Если в колонках содержатся ссылки на объекты базы (например, СправочникСсылка), при десериализации вы получите «битые» ссылки, так как УИД объектов в разных базах могут не совпадать.
Если требуется уменьшить объем передаваемых данных или упаковать таблицу в стандартный XML-формат, можно поместить таблицу значений в ХранилищеЗначения внутри COM-соединения, а затем получить его строковое представление с помощью метода XMLСтрока.
Проанализируем пошаговый алгоритм выполнения этой операции:
ХранилищеЗначения во внешней базе.XMLСтрока.XMLЗначение, разворачивая хранилище.Посмотрим на пример реализации данного подхода:
// Создание и заполнение таблицы во внешней базе
ТаблицаCOM = Соединение82.NewObject("ТаблицаЗначений");
// (Заполнение колонок и строк...)
// Создаем ХранилищеЗначения в контексте COM-базы
ХранилищеCOM = Соединение82.NewObject("ХранилищеЗначения", ТаблицаCOM);
// Получаем XML-строку от хранилища
СериализованнаяСтрока = Соединение82.XMLСтрока(ХранилищеCOM);
// В текущей базе восстанавливаем ХранилищеЗначения и получаем из него таблицу
ХранилищеЛокальное = XMLЗначение(Тип("ХранилищеЗначения"), СериализованнаяСтрока);
ТаблицаЛокальная = ХранилищеЛокальное.Получить();
Для универсальной работы с XML-структурами можно использовать механизм сериализации XDTO. В этом случае функции сериализации и чтения XML оформляются на стороне каждой из баз.
Пример функций сериализации и десериализации данных:
&НаСервереБезКонтекста
Функция СериализоватьДанные(Объект)
ХДТО = СериализаторXDTO.ЗаписатьXDTO(Объект);
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();
ФабрикаXDTO.ЗаписатьXML(ЗаписьXML, ХДТО);
Возврат ЗаписьXML.Закрыть();
КонецФункции
&НаСервереБезКонтекста
Функция ДесериализоватьДанные(СтрокаXML)
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(СтрокаXML);
Данные = СериализаторXDTO.ПрочитатьXML(ЧтениеXML);
ЧтениеXML.Закрыть();
Возврат Данные;
КонецФункции
Чтобы задействовать этот механизм при работе с COM-соединением, сериализацию необходимо вызывать в контексте внешней базы (например, через экспортную функцию общего модуля внешнего узла), чтобы вернуть в вызывающую базу готовый текст XML.
УникальныйИдентификатор или наименования).ЗаписьXML, ЧтениеXML, ТаблицаЗначений нельзя напрямую передавать в локальные методы вашей базы из контекста COM.