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