При работе с интеграциями в среде 1С часто возникает задача получения данных из удаленной информационной базы. Одной из самых распространенных проблем при использовании технологии COM-соединения является передача параметров в запрос, особенно когда речь идет о сложных типах данных, таких как субконто. Давайте подробно разберем, почему нельзя просто передать ссылку из текущей базы во внешнюю и какими способами можно решить эту задачу.
Важно понимать природу COM-соединения. Когда мы подключаемся к другой базе, мы создаем отдельный процесс с собственным адресным пространством и контекстом данных. Ссылка в 1С (объект типа СправочникСсылка) — это не просто идентификатор, это объект, привязанный к конкретной базе данных. Попытка передать локальную ссылку в параметр запроса внешнего соединения приведет к ошибке или к тому, что запрос не найдет данных, так как внешняя база «не знает», что делать с чужим идентификатором. Нам необходимо найти «отражение» нашего объекта во внешней базе.
Это самый простой и часто используемый метод. Если мы знаем, что справочники в обеих базах синхронизированы по текстовым полям, мы можем выполнить поиск объекта непосредственно через COM-объект внешней базы. Рассмотрим пример реализации, основываясь на коде из обсуждения:
// Создаем подключение
Подключение = СОединениеСВнешнейБазой();
// Создаем объект запроса во внешней базе
Запрос = Подключение.NewObject("Запрос");
Запрос.Текст = "ВЫБРАТЬ * ИЗ РегистрБухгалтерии.Хозрасчетный.Остатки(&Дата, Счет = &Счет, , Субконто1 = &Субконто1)";
// Устанавливаем параметры
Запрос.УстановитьПараметр("Дата", ДатаОкончания);
// Поиск счета по коду (рекомендуется вместо наименования)
СчетВнешний = Подключение.ПланыСчетов.Хозрасчетный.НайтиПоКоду("41.01");
Запрос.УстановитьПараметр("Счет", СчетВнешний);
// Поиск субконто по наименованию
// Предположим, Субконто1 в локальной базе — это Контрагент
ИмяКонтрагента = Строка(Объект.Контрагент.Наименование);
СубконтоВнешнее = Подключение.Справочники.Контрагенты.НайтиПоНаименованию(ИмяКонтрагента);
Если Не СубконтоВнешнее.Пустая() Тогда
Запрос.УстановитьПараметр("Субконто1", СубконтоВнешнее);
КонецЕсли;
Важный нюанс: поиск по наименованию может быть неточным, если в базе есть дубли. Поиск по коду считается более надежным, однако стоит учитывать возможные префиксы в разных базах.
Если базы являются идентичными (например, это распределенная информационная база или копия), то самый правильный и надежный способ — это поиск по UUID. Уникальный идентификатор объекта неизменен между базами в рамках обмена.
Проанализируем шаги для реализации этого метода:
UUID объекта в текущей базе и преобразуем его в строку.UUID из строки и получаем ссылку.
// 1. Получаем строковое представление GUID локального объекта
ЛокальныйGUID = Строка(Объект.Субконто1.УникальныйИдентификатор());
// 2. Во внешней базе создаем объект UUID и находим ссылку
// Обратите внимание: метод NewObject вызывается у COM-соединения
ВнешнийUUID = Подключение.NewObject("UUID", ЛокальныйGUID);
// 3. Получаем ссылку в зависимости от типа метаданных
// В данном примере ищем в справочнике Номенклатура
СубконтоВнешнее = Подключение.Справочники.Номенклатура.ПолучитьСсылку(ВнешнийUUID);
// Проверяем, существует ли такой объект во внешней базе
Если Подключение.XMLСтрока(СубконтоВнешнее) = Подключение.XMLСтрока(Подключение.Справочники.Номенклатура.ПустаяСсылка()) Тогда
// Объект не найден, обрабатываем ситуацию
Иначе
Запрос.УстановитьПараметр("Субконто1", СубконтоВнешнее);
КонецЕсли;
Зачастую Субконто имеет составной тип данных, и мы заранее не знаем, в каком справочнике искать значение. В этом случае нам нужно программно определить имя метаданных объекта в локальной базе и обратиться к соответствующему менеджеру во внешней.
Разберем, как это сделать универсально:
// Функция для поиска объекта во внешней базе по локальной ссылке
Функция НайтиОбъектВоВнешнейБазе(ВнешнееСоединение, ЛокальнаяСсылка)
Если ЛокальнаяСсылка.Пустая() Тогда
Возврат Неопределено;
КонецЕсли;
// Получаем имя метаданных (например, "Контрагенты" или "Номенклатура")
ИмяМетаданных = ЛокальнаяСсылка.Метаданные().Имя;
ТипМетаданных = "";
Если Метаданные.Справочники.Содержит(ЛокальнаяСсылка.Метаданные()) Тогда
ТипМетаданных = "Справочники";
ИначеЕсли Метаданные.Документы.Содержит(ЛокальнаяСсылка.Метаданные()) Тогда
ТипМетаданных = "Документы";
КонецЕсли;
Если ТипМетаданных = "" Тогда
Возврат Неопределено;
КонецЕсли;
// Получаем GUID
СтрокаGUID = Строка(ЛокальнаяСсылка.УникальныйИдентификатор());
ВнешнийUUID = ВнешнееСоединение.NewObject("UUID", СтрокаGUID);
// Динамическое обращение к менеджеру объекта через квадратные скобки
Возврат ВнешнееСоединение[ТипМетаданных][ИмяМетаданных].ПолучитьСсылку(ВнешнийUUID);
КонецФункции
При установке параметров запроса важно помнить, что локальные значения Null или Неопределено могут некорректно восприниматься внешним запросом. Чтобы избежать ошибок типизации, рекомендуется использовать значения непосредственно из COM-соединения:
Запрос.УстановитьПараметр("Пар", Подключение.Null);Запрос.УстановитьПараметр("Пар", Подключение.Undefined);Выясним одну важную деталь: каждый вызов метода через COM (например, НайтиПоНаименованию) — это сетевой запрос, который занимает время. Если вам нужно передать массив из 100 субконто, выполнение 100 отдельных поисков существенно замедлит работу обработки.
Проанализируем ситуацию: как сделать быстрее? Вместо поиска каждого элемента по отдельности, рассмотрите возможность передачи во внешнюю базу массива GUID-строк. Затем во внешней базе можно запустить вспомогательный запрос, который преобразует эти строки в ссылки одним пакетом, или использовать временные таблицы. Это сократит количество обращений к COM-интерфейсу и значительно ускорит выполнение кода.
Для успешной передачи субконто через COM-соединение следует придерживаться алгоритма:
Пустая() перед передачей в запрос.НайтиПо..., стараясь группировать данные.