При организации обмена между базами данных 1С с использованием технологии V83.COMConnector разработчики часто сталкиваются с трудностями при передаче сложных типов данных. Одной из таких задач является перенос содержимого реквизитов с типом ХранилищеЗначения (например, при переносе прикрепленных файлов, изображений или дополнительных сведений из справочника Хранилище дополнительной информации).
Прямое присвоение значения реквизита из COM-объекта в объект базы-приемника невозможно, так как COM-сервер возвращает COM-объект (прокси), который не может быть напрямую записан в базу-приемник. Разберем различные способы решения этой задачи, их преимущества, ограничения и особенности реализации.
Проанализируем самый лаконичный способ, который основан на стандартных функциях платформы XMLСтрока и XMLЗначение. Идея заключается в том, чтобы сериализовать объект ХранилищеЗначения в текстовую XML-строку на стороне базы-источника через вызов ее контекста, а затем восстановить его в базе-приемнике.
Рассмотрим пример кода:
// конн - установленное COM-соединение с базой-источником
// Выгружаем ХранилищеЗначения в строку XML через контекст COM-соединения
СтрокаXML = конн.XMLСтрока(СтрокаТЗ.Хранилище);
// В базе-приемнике преобразуем строку обратно в объект типа ХранилищеЗначения
ПриемникОбъект.Хранилище = XMLЗначение(Тип("ХранилищеЗначения"), СтрокаXML);
Важные нюансы использования данного способа:
ДвоичныеДанные). Если внутри хранилища записана ссылка или прикладной объект базы-источника, метод XMLЗначение завершится ошибкой либо создаст некорректную битую ссылку из-за несовпадения внутренних идентификаторов баз.Разберем по шагам альтернативный и более контролируемый вариант. Если в хранилище находятся файлы или картинки (тип ДвоичныеДанные), мы можем явно извлечь их на стороне источника, перевести в строку Base64 и упаковать в новое хранилище на стороне приемника с нужной степенью сжатия.
Посмотрим на пример реализации:
// 1. Извлекаем данные из ХранилищаЗначения в контексте базы-источника
ДвоичныеДанныеИсточника = СтрокаТЗ.Хранилище.Получить();
Если ДвоичныеДанныеИсточника <> Неопределено Тогда
// 2. Преобразуем ДвоичныеДанные в строку Base64 методами базы-источника
СтрокаBase64 = конн.Base64Строка(ДвоичныеДанныеИсточника);
// 3. Восстанавливаем ДвоичныеДанные в базе-приемнике
ДвоичныеДанныеПриемника = Base64Значение(СтрокаBase64);
// 4. Помещаем в ХранилищеЗначения с явным указанием степени сжатия
ПриемникОбъект.Хранилище = Новый ХранилищеЗначения(
ДвоичныеДанныеПриемника,
СтепеньСжатияХранилищаЗначения.Сжатие9
);
КонецЕсли;
Этот подход позволяет гибко управлять сжатием данных (СтепеньСжатияХранилищаЗначения) и точно контролировать тип извлекаемых данных.
Когда речь идет о переносе файлов большого размера (сканы документов, PDF-файлы, архивы от нескольких десятков мегабайт), передача гигантских строк через COM-интерфейс может приводить к ошибкам «Недостаточно памяти». В таких ситуациях наиболее надежным решением является выгрузка во временный файл на диске.
Рассмотрим алгоритм передачи через файловую систему:
ДвоичныеДанные из хранилища и сохраняем их во временный файл на доступном сетевом ресурсе методом Записать().ДвоичныеДанные из этого файла конструктором Новый ДвоичныеДанные(ПутьКФайлу).
// Получаем бинарные данные из хранилища источника
ДвоичныеДанныеИсточника = СтрокаТЗ.Хранилище.Получить();
Если ДвоичныеДанныеИсточника <> Неопределено Тогда
ИмяВременногоФайла = ПолучитьИмяВременногоФайла();
// Записываем файл на диск через метод объекта источника
ДвоичныеДанныеИсточника.Записать(ИмяВременногоФайла);
// Считываем файл в базе-приемнике
ДвоичныеДанныеПриемника = Новый ДвоичныеДанные(ИмяВременногоФайла);
ПриемникОбъект.Хранилище = Новый ХранилищеЗначения(ДвоичныеДанныеПриемника);
// Очищаем временный файл
УдалитьФайлы(ИмяВременногоФайла);
КонецЕсли;
Если в ХранилищеЗначения хранится сложная структура, список значений или таблица простых типов, для надежной передачи структуры без потери типизации целесообразно использовать объект СериализаторXDTO.
Посмотрим, как организовать такую передачу:
// В базе-источнике извлекаем структуру и сериализуем в XML через XDTO
ЗначениеХранилища = СтрокаТЗ.Хранилище.Получить();
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();
конн.СериализаторXDTO.ЗаписатьXML(ЗаписьXML, ЗначениеХранилища);
СтрокаXML = ЗаписьXML.Закрыть();
// В базе-приемнике десериализуем XML обратно в структуру
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(СтрокаXML);
ВосстановленноеЗначение = СериализаторXDTO.ПрочитатьXML(ЧтениеXML);
ЧтениеXML.Закрыть();
ПриемникОбъект.Хранилище = Новый ХранилищеЗначения(ВосстановленноеЗначение);
При проектировании интеграций через COM важно помнить о системных ограничениях данной технологии:
В современной разработке на платформе 1С для передачи двоичных данных и содержимого хранилищ вместо COM рекомендуется использовать платформонезависимые HTTP-сервисы или Web-сервисы, которые позволяют передавать поток байтов без ограничений разрядности и операционной системы.