Работа с COM-соединением в 1С — это классический способ интеграции и переноса данных между базами. Однако разработчики часто сталкиваются с ситуацией, когда при получении данных из внешней базы вместо ссылок на объекты (справочники, документы) они видят пугающую надпись «Объект не найден». При этом в базе-источнике эти объекты существуют и вполне исправны.
В этой статье мы подробно разберем причины возникновения этой проблемы, проанализируем механизмы передачи данных через COM-границу и рассмотрим несколько надежных способов корректного получения информации.
Рассмотрим ситуацию, с которой столкнулся автор темы. При выполнении запроса во внешней базе через COM-соединение и попытке выгрузить результат в таблицу значений в текущую базу, часть данных отображается некорректно. Основная причина здесь кроется в природе ссылочных типов данных 1С.
Разберем по шагам, что происходит «под капотом»:
РезультатКом.Выгрузить() создается Proxy-объект таблицы значений. Сами данные физически остаются в базе-источнике, а база-приемник получает лишь «ярлыки» для обращения к ним.ЗначениеВСтрокуВнутр() передает не только GUID объекта, но и внутренний идентификатор типа метаданных. Если базы не являются полными клонами (созданными из одного .dt файла), ID справочника Номенклатура в одной базе может отличаться от ID в другой, даже если названия и реквизиты идентичны. Система просто не может сопоставить «чужую» ссылку со своим объектом метаданных.Важный момент: Примитивные типы данных (строка, число, дата, булево) передаются через COM без проблем, так как они универсальны для любой среды. Именно поэтому часть информации у автора выгружалась нормально.
Если конфигурации баз идентичны или схожи, самый простой и надежный способ — отказаться от передачи ссылок в запросе. Вместо этого мы будем получать уникальные текстовые или числовые идентификаторы объектов, такие как Код или Артикул.
Проанализируем пример кода для базы-источника:
// В запросе выбираем не Ссылку, а Код и Наименование
ТекстЗапроса = "ВЫБРАТЬ
| Номенклатура.Код КАК Код,
| Номенклатура.Наименование КАК Наименование
|ИЗ
| Справочник.Номенклатура КАК Номенклатура";
ЗапросКом = КомСоединение.NewObject("Запрос");
ЗапросКом.Текст = ТекстЗапроса;
РезультатТЗ = ЗапросКом.Выполнить().Выгрузить();
// Теперь в РезультатТЗ лежат строки и числа, которые база-приемник понимает
Для Каждого Стр Из РезультатТЗ Цикл
// Ищем объект уже в локальной базе по коду
ЛокальнаяСсылка = Справочники.Номенклатура.НайтиПоКоду(Стр.Код);
Если ЛокальнаяСсылка.Пустая() Тогда
// Обработка ситуации, если объект не найден
КонецЕсли;
КонецЦикла;
Если поиск по коду не подходит (например, коды могут дублироваться или отсутствовать), следует использовать УникальныйИдентификатор (GUID). Это гарантированный способ сопоставить объекты в двух базах.
Выясним, как правильно передать GUID через COM-границу. Прямая передача объекта УникальныйИдентификатор через COM может работать нестабильно, поэтому лучше использовать преобразование в строку через XMLString.
Рассмотрим по шагам алгоритм действий:
УникальныйИдентификатор из этой строки и ищем (или создаем) по нему ссылку.Пример реализации:
// На стороне базы-источника (через COM-объект)
СсылкаИзКома = Выборка.Ссылка;
СтрокаGUID = КомСоединение.XMLString(СсылкаИзКома);
// На стороне базы-приемника
НовыйGUID = Новый УникальныйИдентификатор(СтрокаGUID);
ЛокальнаяСсылка = Справочники.Номенклатура.ПолучитьСсылку(НовыйGUID);
// Проверим, существует ли объект реально
ОбъектМетаданных = ЛокальнаяСсылка.ПолучитьОбъект();
Если ОбъектМетаданных = Неопределено Тогда
// Объекта с таким GUID в этой базе еще нет - нужно создавать или сопоставлять иначе
КонецЕсли;
Если вы работаете на платформе 8.3, наиболее технологичным решением будет сериализация данных в формат JSON на стороне источника. Это полностью разрывает зависимость от контекста COM-соединения и передает чистые данные.
Разберем этот метод подробнее. Вместо того чтобы перебирать таблицу значений через COM (что крайне медленно из-за постоянных RPC-вызовов), мы заставим внешнюю базу сформировать одну большую строку JSON.
Посмотрим на пример логики:
// Внешняя база формирует массив структур и упаковывает в JSON
ЗаписьJSON = КомСоединение.NewObject("ЗаписьJSON");
ЗаписьJSON.УстановитьСтроку();
// ... логика обхода результата запроса и заполнения массива структур ...
КомСоединение.ЗаписатьJSON(ЗаписьJSON, МассивРезультатов);
СтрокаДанных = ЗаписьJSON.Закрыть();
// В базе-приемнике читаем строку
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(СтрокаДанных);
ДанныеВнешнейБазы = ПрочитатьJSON(ЧтениеJSON);
Этот способ работает в десятки раз быстрее, так как обращение через COM происходит всего один раз для получения всей строки данных, а не для каждой ячейки таблицы.
Работа через COM-соединение накладывает определенные ограничения. Чтобы избежать ошибок и зависаний, придерживайтесь следующих правил:
Стр.Наименование) — это сетевой запрос между процессами. Старайтесь выгружать данные в массив или структуру на стороне источника и передавать их целиком.Неопределено.ВыгрузкаЗагрузкаДанныхXML. Она работает напрямую с XML-сериализацией и автоматически решает проблемы с идентификаторами типов метаданных.Подводя итог, отметим: ошибка «Объект не найден» — это не сбой системы, а логичное следствие того, что ссылки одной базы не имеют смысла в другой. Используйте примитивные типы (строки, GUID) для передачи данных, и ваши интеграции будут работать стабильно.