Как устранить ошибку «Объект не найден» при выполнении запроса через COM-соединение?

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

Работа с COM-соединением в 1С — это классический способ интеграции и переноса данных между базами. Однако разработчики часто сталкиваются с ситуацией, когда при получении данных из внешней базы вместо ссылок на объекты (справочники, документы) они видят пугающую надпись «Объект не найден». При этом в базе-источнике эти объекты существуют и вполне исправны.

В этой статье мы подробно разберем причины возникновения этой проблемы, проанализируем механизмы передачи данных через COM-границу и рассмотрим несколько надежных способов корректного получения информации.

Почему возникает ошибка «Объект не найден»?

Рассмотрим ситуацию, с которой столкнулся автор темы. При выполнении запроса во внешней базе через COM-соединение и попытке выгрузить результат в таблицу значений в текущую базу, часть данных отображается некорректно. Основная причина здесь кроется в природе ссылочных типов данных 1С.

Разберем по шагам, что происходит «под капотом»:

  1. Разные адресные пространства: Ссылка в 1С — это не просто запись в базе данных, это объект, содержащий уникальный идентификатор (GUID) и информацию о типе метаданных. Когда вы получаете ссылку из базы «А» в базе «Б», база «Б» ничего не знает об этом объекте. В её таблицах этой записи просто не существует.
  2. Механизм маршалинга: При выполнении команды РезультатКом.Выгрузить() создается Proxy-объект таблицы значений. Сами данные физически остаются в базе-источнике, а база-приемник получает лишь «ярлыки» для обращения к ним.
  3. Проблема внутреннего представления: Использование метода ЗначениеВСтрокуВнутр() передает не только GUID объекта, но и внутренний идентификатор типа метаданных. Если базы не являются полными клонами (созданными из одного .dt файла), ID справочника Номенклатура в одной базе может отличаться от ID в другой, даже если названия и реквизиты идентичны. Система просто не может сопоставить «чужую» ссылку со своим объектом метаданных.

Важный момент: Примитивные типы данных (строка, число, дата, булево) передаются через COM без проблем, так как они универсальны для любой среды. Именно поэтому часть информации у автора выгружалась нормально.

Решение №1: Передача данных через примитивные типы (Коды и Наименования)

Если конфигурации баз идентичны или схожи, самый простой и надежный способ — отказаться от передачи ссылок в запросе. Вместо этого мы будем получать уникальные текстовые или числовые идентификаторы объектов, такие как Код или Артикул.

Проанализируем пример кода для базы-источника:


// В запросе выбираем не Ссылку, а Код и Наименование
ТекстЗапроса = "ВЫБРАТЬ
               |    Номенклатура.Код КАК Код,
               |    Номенклатура.Наименование КАК Наименование
               |ИЗ
               |    Справочник.Номенклатура КАК Номенклатура";

ЗапросКом = КомСоединение.NewObject("Запрос");
ЗапросКом.Текст = ТекстЗапроса;
РезультатТЗ = ЗапросКом.Выполнить().Выгрузить();

// Теперь в РезультатТЗ лежат строки и числа, которые база-приемник понимает
Для Каждого Стр Из РезультатТЗ Цикл
    // Ищем объект уже в локальной базе по коду
    ЛокальнаяСсылка = Справочники.Номенклатура.НайтиПоКоду(Стр.Код);
    Если ЛокальнаяСсылка.Пустая() Тогда
        // Обработка ситуации, если объект не найден
    КонецЕсли;
КонецЦикла;

Решение №2: Использование XMLString и Уникального Идентификатора

Если поиск по коду не подходит (например, коды могут дублироваться или отсутствовать), следует использовать УникальныйИдентификатор (GUID). Это гарантированный способ сопоставить объекты в двух базах.

Выясним, как правильно передать GUID через COM-границу. Прямая передача объекта УникальныйИдентификатор через COM может работать нестабильно, поэтому лучше использовать преобразование в строку через XMLString.

Рассмотрим по шагам алгоритм действий:

  1. В базе-источнике преобразуем ссылку в строку GUID.
  2. Передаем эту строку в базу-приемник.
  3. В базе-приемнике создаем новый объект УникальныйИдентификатор из этой строки и ищем (или создаем) по нему ссылку.

Пример реализации:


// На стороне базы-источника (через COM-объект)
СсылкаИзКома = Выборка.Ссылка;
СтрокаGUID = КомСоединение.XMLString(СсылкаИзКома);

// На стороне базы-приемника
НовыйGUID = Новый УникальныйИдентификатор(СтрокаGUID);
ЛокальнаяСсылка = Справочники.Номенклатура.ПолучитьСсылку(НовыйGUID);

// Проверим, существует ли объект реально
ОбъектМетаданных = ЛокальнаяСсылка.ПолучитьОбъект();
Если ОбъектМетаданных = Неопределено Тогда
    // Объекта с таким GUID в этой базе еще нет - нужно создавать или сопоставлять иначе
КонецЕсли;

Решение №3: Сериализация через JSON (для современных платформ 8.3)

Если вы работаете на платформе 8.3, наиболее технологичным решением будет сериализация данных в формат JSON на стороне источника. Это полностью разрывает зависимость от контекста COM-соединения и передает чистые данные.

Разберем этот метод подробнее. Вместо того чтобы перебирать таблицу значений через COM (что крайне медленно из-за постоянных RPC-вызовов), мы заставим внешнюю базу сформировать одну большую строку JSON.

Посмотрим на пример логики:


// Внешняя база формирует массив структур и упаковывает в JSON
ЗаписьJSON = КомСоединение.NewObject("ЗаписьJSON");
ЗаписьJSON.УстановитьСтроку();
// ... логика обхода результата запроса и заполнения массива структур ...
КомСоединение.ЗаписатьJSON(ЗаписьJSON, МассивРезультатов);
СтрокаДанных = ЗаписьJSON.Закрыть();

// В базе-приемнике читаем строку
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(СтрокаДанных);
ДанныеВнешнейБазы = ПрочитатьJSON(ЧтениеJSON);

Этот способ работает в десятки раз быстрее, так как обращение через COM происходит всего один раз для получения всей строки данных, а не для каждой ячейки таблицы.

Рекомендации по повышению производительности

Работа через COM-соединение накладывает определенные ограничения. Чтобы избежать ошибок и зависаний, придерживайтесь следующих правил:

Подводя итог, отметим: ошибка «Объект не найден» — это не сбой системы, а логичное следствие того, что ссылки одной базы не имеют смысла в другой. Используйте примитивные типы (строки, GUID) для передачи данных, и ваши интеграции будут работать стабильно.

← На главную