Как передать значение субконто в запрос через COM-соединение

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

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

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

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

Способ 1. Поиск по наименованию или коду

Это самый простой и часто используемый метод. Если мы знаем, что справочники в обеих базах синхронизированы по текстовым полям, мы можем выполнить поиск объекта непосредственно через COM-объект внешней базы. Рассмотрим пример реализации, основываясь на коде из обсуждения:


// Создаем подключение
Подключение = СОединениеСВнешнейБазой();

// Создаем объект запроса во внешней базе
Запрос = Подключение.NewObject("Запрос");
Запрос.Текст = "ВЫБРАТЬ * ИЗ РегистрБухгалтерии.Хозрасчетный.Остатки(&Дата, Счет = &Счет, , Субконто1 = &Субконто1)";

// Устанавливаем параметры
Запрос.УстановитьПараметр("Дата", ДатаОкончания);

// Поиск счета по коду (рекомендуется вместо наименования)
СчетВнешний = Подключение.ПланыСчетов.Хозрасчетный.НайтиПоКоду("41.01");
Запрос.УстановитьПараметр("Счет", СчетВнешний);

// Поиск субконто по наименованию
// Предположим, Субконто1 в локальной базе — это Контрагент
ИмяКонтрагента = Строка(Объект.Контрагент.Наименование);
СубконтоВнешнее = Подключение.Справочники.Контрагенты.НайтиПоНаименованию(ИмяКонтрагента);

Если Не СубконтоВнешнее.Пустая() Тогда
    Запрос.УстановитьПараметр("Субконто1", СубконтоВнешнее);
КонецЕсли;

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

Способ 2. Поиск по уникальному идентификатору (GUID)

Если базы являются идентичными (например, это распределенная информационная база или копия), то самый правильный и надежный способ — это поиск по UUID. Уникальный идентификатор объекта неизменен между базами в рамках обмена.

Проанализируем шаги для реализации этого метода:

  1. Получаем UUID объекта в текущей базе и преобразуем его в строку.
  2. Передаем эту строку во внешнюю базу.
  3. Во внешней базе восстанавливаем UUID из строки и получаем ссылку.

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

// 2. Во внешней базе создаем объект UUID и находим ссылку
// Обратите внимание: метод NewObject вызывается у COM-соединения
ВнешнийUUID = Подключение.NewObject("UUID", ЛокальныйGUID);

// 3. Получаем ссылку в зависимости от типа метаданных
// В данном примере ищем в справочнике Номенклатура
СубконтоВнешнее = Подключение.Справочники.Номенклатура.ПолучитьСсылку(ВнешнийUUID);

// Проверяем, существует ли такой объект во внешней базе
Если Подключение.XMLСтрока(СубконтоВнешнее) = Подключение.XMLСтрока(Подключение.Справочники.Номенклатура.ПустаяСсылка()) Тогда
    // Объект не найден, обрабатываем ситуацию
Иначе
    Запрос.УстановитьПараметр("Субконто1", СубконтоВнешнее);
КонецЕсли;

Способ 3. Универсальное определение типа метаданных

Зачастую Субконто имеет составной тип данных, и мы заранее не знаем, в каком справочнике искать значение. В этом случае нам нужно программно определить имя метаданных объекта в локальной базе и обратиться к соответствующему менеджеру во внешней.

Разберем, как это сделать универсально:


// Функция для поиска объекта во внешней базе по локальной ссылке
Функция НайтиОбъектВоВнешнейБазе(ВнешнееСоединение, ЛокальнаяСсылка)
    
    Если ЛокальнаяСсылка.Пустая() Тогда
        Возврат Неопределено;
    КонецЕсли;
    
    // Получаем имя метаданных (например, "Контрагенты" или "Номенклатура")
    ИмяМетаданных = ЛокальнаяСсылка.Метаданные().Имя;
    ТипМетаданных = "";
    
    Если Метаданные.Справочники.Содержит(ЛокальнаяСсылка.Метаданные()) Тогда
        ТипМетаданных = "Справочники";
    ИначеЕсли Метаданные.Документы.Содержит(ЛокальнаяСсылка.Метаданные()) Тогда
        ТипМетаданных = "Документы";
    КонецЕсли;
    
    Если ТипМетаданных = "" Тогда
        Возврат Неопределено;
    КонецЕсли;
    
    // Получаем GUID
    СтрокаGUID = Строка(ЛокальнаяСсылка.УникальныйИдентификатор());
    ВнешнийUUID = ВнешнееСоединение.NewObject("UUID", СтрокаGUID);
    
    // Динамическое обращение к менеджеру объекта через квадратные скобки
    Возврат ВнешнееСоединение[ТипМетаданных][ИмяМетаданных].ПолучитьСсылку(ВнешнийUUID);
    
КонецФункции

Работа с системными значениями (Null, Неопределено)

При установке параметров запроса важно помнить, что локальные значения Null или Неопределено могут некорректно восприниматься внешним запросом. Чтобы избежать ошибок типизации, рекомендуется использовать значения непосредственно из COM-соединения:

Оптимизация производительности

Выясним одну важную деталь: каждый вызов метода через COM (например, НайтиПоНаименованию) — это сетевой запрос, который занимает время. Если вам нужно передать массив из 100 субконто, выполнение 100 отдельных поисков существенно замедлит работу обработки.

Проанализируем ситуацию: как сделать быстрее? Вместо поиска каждого элемента по отдельности, рассмотрите возможность передачи во внешнюю базу массива GUID-строк. Затем во внешней базе можно запустить вспомогательный запрос, который преобразует эти строки в ссылки одним пакетом, или использовать временные таблицы. Это сократит количество обращений к COM-интерфейсу и значительно ускорит выполнение кода.

Резюме

Для успешной передачи субконто через COM-соединение следует придерживаться алгоритма:

  1. Определить, идентичны ли базы. Если да — использовать поиск по UUID.
  2. Если базы разные — использовать поиск по Коду или Наименованию, предварительно определив тип справочника через метаданные.
  3. Всегда проверять результат поиска на Пустая() перед передачей в запрос.
  4. Для ускорения работы минимизировать количество вызовов методов НайтиПо..., стараясь группировать данные.
← На главную