Работа с внешними источниками данных через COM-соединение (V83.COMConnector) является стандартной задачей при интеграции различных информационных баз 1С. Однако начинающие разработчики часто сталкиваются с трудностями при попытке получить привычные данные, такие как текстовое представление ссылки или имя типа документа, поскольку объекты на "той стороне" соединения ведут себя иначе, чем в контексте текущей базы. В данной статье мы подробно разберем, как корректно извлекать информацию об объектах через COM, минимизируя ошибки и потерю производительности.
Когда нам нужно получить строку вида "Реализация №5466 от 01.01.2019", обычное обращение к объекту или попытка приведения типа на стороне вызывающей базы не сработает. Это связано с тем, что COM-объект ссылки не преобразуется автоматически в строку в контексте вашей текущей сессии. Чтобы получить человекочитаемое представление, мы должны использовать методы глобального контекста той базы, к которой подключились.
Проанализируем наиболее эффективный способ. Для этого обратимся к методу String() самого объекта COM-соединения. Рассмотрим пример кода:
// Предположим, МоёКомСоединение уже установлено
// МояКомСсылка — это объект ссылки, полученный из внешней базы
ПредставлениеОбъекта = МоёКомСоединение.String(МояКомСсылка);
Сообщить(ПредставлениеОбъекта); // Выведет: Реализация товаров и услуг...
Важно понимать, что метод String() в данном случае выполняется на стороне сервера COM-соединения и возвращает уже готовую строку, которую ваша текущая база может легко обработать. Использование стандартной функции Строка(МояКомСсылка) в локальном коде вернет лишь техническое описание COM-объекта, что не является полезным для пользователя.
Для однозначной идентификации объекта в разных базах (например, для синхронизации) нам требуется получить его УникальныйИдентификатор. Напрямую обратиться к свойству УникальныйИдентификатор() можно, но результат будет передан как специфический COM-объект. Чтобы работать с ним как со строкой, следует выполнить преобразование на удаленной стороне.
Разберем, как это сделать правильно:
// Получаем UUID как COM-объект и сразу преобразуем его в строку
СтрокаGUID = МоёКомСоединение.String(МояКомСсылка.UUID());
Полученную строку можно сохранить или использовать для поиска этого же объекта при следующем подключении. Если же вам нужно воссоздать ссылку в текущей базе (при условии, что конфигурации идентичны), мы можем использовать следующий алгоритм:
УникальныйИдентификатор в локальной базе.
// Пример реконструкции ссылки
GUIDСтрокой = МоёКомСоединение.String(МояКомСсылка.UUID());
НовыйУИ = Новый УникальныйИдентификатор(GUIDСтрокой);
ЛокальнаяСсылка = Документы.РеализацияТоваровУслуг.ПолучитьСсылку(НовыйУИ);
Часто при обмене данными необходимо программно определить, к какому типу относится полученная ссылка (например, это "РеализацияТоваровУслуг" или "ПоступлениеТоваровУслуг"). Попытка вызвать ТипЗнч() в локальном коде вернет общий тип COMОбъект. Чтобы узнать истинный тип, мы должны обратиться к метаданным удаленной базы.
Рассмотрим два способа получения имени типа:
Способ 1. Через метод Metadata() ссылки:
Каждая ссылка в COM-соединении имеет доступ к своим метаданным. Мы можем напрямую запросить имя объекта:
ИмяТипа = МояКомСсылка.Metadata().Name;
// Вернет, например, "РеализацияТоваровУслуг"
Способ 2. Через глобальный метод TypeValue:
Если нам нужно сравнить тип объекта с конкретным типом, лучше использовать метод TypeValue, который доступен через объект соединения:
ТипОбъекта = МоёКомСоединение.TypeValue(МояКомСсылка);
Если ТипОбъекта = МоёКомСоединение.Type("DocumentRef.РеализацияТоваровУслуг") Тогда
// Выполняем логику для конкретного документа
КонецЕсли;
В некоторых случаях удобно передавать данные через XML-строку. Метод XMLСтрока() позволяет быстро получить строковое представление ссылки, которое включает в себя UUID. Однако, как отмечают разработчики, при прямом вызове XMLСтрока(МояКомСсылка) может возникнуть ошибка преобразования. Выясним причину: локальная база не знает, как сериализовать чужой COM-объект.
Решение заключается в вызове этого метода именно на стороне COM-соединения:
ТекСтрокаXML = МоёКомСоединение.XMLСтрока(МояКомСсылка);
Этот метод возвращает внутреннее представление ссылки, которое часто используется в механизмах обмена данными. Но стоит помнить, что для простого отображения пользователю метод String() подходит гораздо лучше.
Одной из главных проблем COM-соединения является низкая скорость работы при большом количестве обращений ("пинг" между процессами). Если нам нужно получить данные для тысячи документов, обращение к каждому свойству (.Number, .Date, .Metadata().Name) по отдельности создаст огромную нагрузку.
Проанализируем ситуацию: каждое обращение через точку к COM-объекту — это отдельный сетевой или межпроцессный вызов. Чтобы ускорить работу, мы можем использовать метод Eval() (Вычислить) или Execute() (Выполнить), чтобы выполнить код целиком на той стороне и вернуть структуру данных.
// Формируем запрос на получение данных одной транзакцией
КодДляВыполнения = "
|Стр = Новый Структура;
|Стр.Вставить(""Представление"", String(Объект));
|Стр.Вставить(""ИмяТипа"", Объект.Metadata().Name);
|Стр.Вставить(""GUID"", String(Объект.UUID()));
|Возврат Стр;";
// Передаем объект в контекст выполнения (если это возможно)
// или используем поиск внутри Eval
Данные = МоёКомСоединение.Eval(СтрЗаменить(КодДляВыполнения, "Объект", "Документы.РеализацияТоваровУслуг.НайтиПоНомеру(""5466"")"));
Совет: Вместо того чтобы запрашивать реквизиты по одному, лучше написать на стороне COM-базы небольшую экспортную функцию в общем модуле, которая будет принимать ссылку и возвращать Структуру или ФиксированнуюСтруктуру со всеми нужными данными. Передача одной структуры через COM работает значительно быстрее, чем десять отдельных вызовов свойств ссылки.
При работе через COM крайне важно проверять ссылки на валидность. Если объект был удален в базе-источнике, но ссылка на него сохранилась в каком-то регистре, обращение к МояКомСсылка.Metadata() вызовет исключение и аварийное завершение скрипта.
Рассмотрим правильный алгоритм проверки:
ValueIsFilled.IsEmpty() (Пустая()) самой ссылки.Попытка...Исключение.
Если МоёКомСоединение.ValueIsFilled(МояКомСсылка) Тогда
Попытка
ИмяТипа = МояКомСсылка.Metadata().Name;
Исключение
Сообщить("Объект не найден в базе-источнике (битая ссылка)");
КонецПопытки;
КонецЕсли;
Иногда даже при правильном коде попытка получить метаданные через COM завершается ошибкой "Класс не зарегистрирован" или ошибками доступа к памяти. Это часто происходит на 64-битных серверах 1С, так как библиотека comcntr.dll по умолчанию может конфликтовать с разрядностью процессов.
Для решения этой проблемы мы рекомендуем:
regsvr32.comcntr.dll и установить в свойствах "Удостоверение" пользователя с правами администратора.Это позволит 64-битному серверу 1С беспрепятственно обращаться к 32-битным или 64-битным объектам COM, обеспечивая стабильное получение ссылок и типов данных из внешних баз.
Подводя итог, можно сказать, что ключ к успешной работе с объектами через COM — это выполнение всех ресурсоемких операций (преобразование в строку, получение метаданных, сериализация) на стороне внешней базы. Это не только решает проблему с типами данных, но и существенно повышает скорость работы вашего решения.