Перенос данных между базами 1С с использованием технологии COM-соединения (Automation) — это классическая задача, с которой сталкиваются разработчики при необходимости синхронизации данных без использования сложных инструментов вроде «1С:Конвертация данных». Однако при работе со связанными справочниками и регистрами возникают нюансы: как сопоставить объекты, если ссылка в COM-базе — это не то же самое, что ссылка в текущей базе? Разберем подробно, как реализовать этот процесс эффективно и с минимальными потерями производительности.
Проанализируем главную сложность: когда мы получаем объект через V83.ComConnector, мы работаем с прокси-объектом. Если в базе-источнике реквизит справочника ссылается на другой справочник, то через COM мы получим ссылку, которая «живет» только внутри того соединения. Мы не можем просто написать Приемник.Контрагент = ИсточникCOM.Контрагент, так как типы данных принадлежат разным пространствам имен.
Выясним причину, по которой прямое сравнение невозможно. Каждая ссылка в 1С характеризуется уникальным идентификатором (GUID). Чтобы сопоставить объекты в двух базах, нам нужно использовать именно этот идентификатор. Рассмотрим алгоритм сопоставления:
Посмотрим на пример кода, который реализует получение идентификатора через COM:
// На стороне базы-приемника
ИдентификаторСтрокой = БазаИсточникCOM.String(ОбъектИсточникCOM.UUID());
НоваяСсылка = Справочники.Контрагенты.ПолучитьСсылку(Новый УникальныйИдентификатор(ИдентификаторСтрокой));
Рассмотрим ситуацию, когда нам нужно перенести справочник «Договоры», который связан со справочником «Контрагенты». Чтобы не получить «битые» ссылки (объект не найден), мы должны применить двухпроходную систему или предварительное создание владельцев.
Разберем по шагам наиболее надежный метод:
Шаг 1: Подготовка данных на стороне источника. Вместо того чтобы перебирать объекты в цикле и обращаться к каждому свойству (что крайне медленно из-за сетевых задержек COM), выполним запрос на стороне COM-базы и выгрузим результат в таблицу значений.
Шаг 2: Обработка связанных данных. Для каждого связанного объекта (например, владельца договора) мы должны сначала проверить его наличие в нашей базе. Проанализируем пример функции для поиска/создания ссылки:
Функция НайтиСоздатьОбъектПоGUID(ИмяСправочника, ИдентификаторСтрокой, COMБаза)
СсылкаВПриемнике = Справочники[ИмяСправочника].ПолучитьСсылку(Новый УникальныйИдентификатор(ИдентификаторСтрокой));
// Проверяем, существует ли объект в базе
Если СсылкаВПриемнике.ПолучитьОбъект() = Неопределено Тогда
// Если нет — создаем или подтягиваем минимальные данные
ОбъектИсточник = COMБаза.Справочники[ИмяСправочника].ПолучитьСсылку(COMБаза.NewObject("UUID", ИдентификаторСтрокой));
// Здесь логика создания нового объекта...
КонецЕсли;
Возврат СсылкаВПриемнике;
КонецФункции
Многие участники обсуждения справедливо замечают, что «чистый» COM работает медленно. Каждое обращение к свойству Объект.Наименование инициирует вызов через границу процессов. Чтобы ускорить процесс, проанализируем ситуацию: не лучше ли передавать данные пакетами?
Вместо ручного копирования реквизитов, воспользуемся сериализацией. Разберем этот подход:
JSON или XML (используя XDTO).Этот метод позволяет сократить количество COM-вызовов в тысячи раз. Посмотрим на пример формирования данных на стороне источника:
// Внутри COM-базы (вызывается из приемника)
Функция ПолучитьДанныеВФорматеJSON(ЗапросТекст) Экспорт
Запрос = НовыйЗапрос(ЗапросТекст);
ТЗ = Запрос.Выполнить().Выгрузить();
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, ТЗ);
Возврат ЗаписьJSON.Закрыть();
КонецФункции
При работе с ведомыми таблицами (например, табличные части или зависимые справочники) удобно использовать кэширование в оперативной памяти. Рассмотрим подробнее, как это работает. Чтобы не обращаться к базе данных для поиска каждой ссылки, мы создаем объект Соответствие.
Ключом в этом соответствии будет GUID из базы-источника, а значением — готовая ссылка в базе-приемнике. Проанализируем алгоритм:
Соответствие, берем готовую ссылку.Соответствие.Это избавляет от избыточных запросов SELECT к базе данных приемника, особенно если у многих записей один и тот же владелец.
Работа с COM-соединением требует аккуратности. Выясним причину возможных сбоев и как их предотвратить:
COMОбъект = Неопределено;), и вызывайте ЗавершитьРаботуСистемы(Ложь) для закрытия процесса, если это необходимо.comcntr.dll.Подводя итог, можно сказать: перенос данных через COM-соединение вполне жизнеспособен, если использовать UUID для синхронизации и минимизировать количество обращений к свойствам объектов, отдавая предпочтение пакетной передаче данных через структуры или JSON.