При разработке механизмов интеграции между различными базами 1С программисты часто сталкиваются с необходимостью передачи ссылок на элементы справочников или документы — для этого есть подсистема синхронизации данных между базами 1С по COM и XML. Особенно актуально это для распределенных информационных баз (РИБ), где УникальныйИдентификатор (GUID) объектов совпадает во всех узлах. Однако при использовании технологии COM-соединения возникает серьезная проблема: передаваемая ссылка «оборачивается» в непрозрачный контейнер COMObject, с которым невозможно работать напрямую в базе-приемнике. В этой статье мы подробно разберем, как преодолеть эти ограничения и корректно сопоставить объекты.
Проанализируем ситуацию: когда мы выполняем запрос через COM-соединение, база-источник возвращает результат. Если в колонке запроса содержится ссылка, то для основной базы она является чужеродным объектом. Система 1С не может автоматически преобразовать COMObject (ссылку из удаленной базы) в локальную ссылку, даже если их внутренние идентификаторы идентичны. Попытка подставить такой объект в локальный запрос или использовать его как параметр метода приведет к ошибке типа или сообщению о том, что метод не найден. Выясним причину: COM-соединение передает данные через маршалинг типов, и сложные типы 1С (такие как СправочникСсылка) не имеют прямого аналога в вызывающей среде, кроме как универсальный интерфейс взаимодействия — решить эти проблемы поможет готовая настройка автоматического обмена данными между базами 1С через COM.
Рассмотрим самый доступный способ решения проблемы. Поскольку в РИБ идентификаторы объектов совпадают, нам достаточно получить строковое представление УникальныйИдентификатор на стороне COM-сервера и передать его как обычную строку (примитивный тип). Рассмотрим пример кода, который позволяет это реализовать:
// Устанавливаем соединение с удаленной базой
COMСоединение = Новый COMОбъект("V83.COMConnector");
БазаИсточник = COMСоединение.Connect(СтрокаПодключения);
// Выполняем запрос на стороне удаленной базы
ЗапросCOM = БазаИсточник.NewObject("Запрос");
ЗапросCOM.Текст = "ВЫБРАТЬ Ссылка ИЗ Справочник.Номенклатура ГДЕ Код = '00001'";
Результат = ЗапросCOM.Выполнить().Выбрать();
Если Результат.Следующий() Тогда
// Используем метод String самого COM-соединения для получения GUID в виде строки
СтрокаGUID = БазаИсточник.String(Результат.Ссылка.УникальныйИдентификатор());
// Теперь в нашей текущей базе восстанавливаем ссылку по строковому GUID
ЛокальныйGUID = Новый УникальныйИдентификатор(СтрокаGUID);
ЛокальнаяСсылка = Справочники.Номенклатура.ПолучитьСсылку(ЛокальныйGUID);
Если Не ЛокальнаяСсылка.Пустая() Тогда
Сообщить("Объект успешно найден: " + ЛокальнаяСсылка);
КонецЕсли;
КонецЕсли;
Важно отметить: мы вызываем метод String() именно у объекта БазаИсточник (COM-соединения). Это заставляет удаленную базу выполнить преобразование объекта в строку на своей стороне и вернуть нам уже готовый примитивный тип String, который 1С понимает без проблем.
Разберем еще более надежный и быстрый метод — использование механизма XML-сериализации. Функция XMLString (или XMLСтрока в русской нотации) возвращает идентификатор ссылки в стандартном формате, который гарантированно одинаков для всех версий платформы. Это позволяет избежать проблем с внутренними форматами представления данных. Посмотрим на реализацию:
// На стороне базы-приемника получаем XML-представление ссылки из COM
СтрокаУИД = БазаИсточник.XMLString(СсылкаИзCOM);
// Восстанавливаем ссылку в локальной базе
Идентификатор = Новый УникальныйИдентификатор(СтрокаУИД);
СсылкаНаОбъект = Справочники.Контрагенты.ПолучитьСсылку(Идентификатор);
Метод XMLString хорош тем, что он работает очень быстро и возвращает чистый GUID без лишних символов, что делает его идеальным для задач синхронизации в РИБ — упростить этот процесс поможет универсальный перенос данных между конфигурациями 1С через COM и HTTP.
Проанализируем типичную ошибку начинающих разработчиков: итерация по результату запроса Выборка.Следующий() внутри цикла в основной базе. Каждый вызов метода через точку от COM-объекта — это сетевой вызов (round-trip), который крайне негативно сказывается на производительности. Если объектов тысячи, обработка может затянуться на часы.
Выясним, как сделать правильно: необходимо минимизировать количество обращений к COM-серверу. Для этого на стороне удаленной базы следует подготовить данные и упаковать их в массив структур или таблицу значений, содержащую только примитивные типы (строки, числа, даты). Посмотрим на пример эффективной передачи данных:
// На стороне удаленной базы создаем структуру для передачи
ДанныеДляПередачи = БазаИсточник.NewObject("Массив");
ЗапросCOM = БазаИсточник.NewObject("Запрос");
ЗапросCOM.Текст = "ВЫБРАТЬ Ссылка, Код, Наименование ИЗ Справочник.ФизическиеЛица";
Выборка = ЗапросCOM.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
СтруктураОбъекта = БазаИсточник.NewObject("Структура");
СтруктураОбъекта.Вставить("GUID", БазаИсточник.XMLString(Выборка.Ссылка));
СтруктураОбъекта.Вставить("Наименование", Выборка.Наименование);
ДанныеДляПередачи.Добавить(СтруктураОбъекта);
КонецЦикла;
// Возвращаем весь массив целиком. На стороне приемника это будет один COM-объект,
// содержащий коллекцию структур с примитивными данными.
Хотя массив и структуры останутся COM-объектами, обращение к свойствам структур с примитивными типами внутри будет происходить значительно быстрее, чем работа с полноценными ссылками 1С через COM.
Рассмотрим ситуацию, когда возникает ошибка «Метод Выполнить() не найден». Это часто происходит, если объект Запрос был создан некорректно или связь с базой была разорвана. Важно помнить следующие правила:
Запрос, Новый УникальныйИдентификатор и другие именно через менеджер COM-соединения (например, БазаИсточник.NewObject("Запрос")).NewObject, Execute, Select, Next), так как это повышает стабильность работы компоненты comcntr.dll.БазаИсточник = Неопределено), чтобы избежать утечек памяти на сервере.Существует еще один метод — ЗначениеВСтрокуВнутр(). Он возвращает полную информацию об объекте в специальном формате 1С. Рассмотрим его использование:
ВнутренняяСтрока = БазаИсточник.ValueToStringInternal(СсылкаИзCOM);
// В основной базе
ЛокальнаяСсылка = ЗначениеИзСтрокиВнутр(ВнутренняяСтрока);
Внимание: Этот метод следует использовать с осторожностью. Внутренний формат может меняться от версии к версии платформы, и он содержит метаданные конкретной конфигурации, что иногда приводит к ошибкам, если структуры метаданных в базах хоть немного различаются.
Мы проанализировали основные способы работы со ссылками через COM-соединение в среде 1С. Подведем итоги: для РИБ-систем наиболее надежным и быстрым способом является передача УникальныйИдентификатор через метод XMLString. Если же вы работаете в современных конфигурациях на платформе 8.3, рассмотрите возможность замены COM-соединения на HTTP-сервисы. Они работают через JSON, что полностью исключает проблемы с типами данных и обеспечивает гораздо более высокую скорость и стабильность обмена данными.