Как передать список значений в запрос при обмене данными через COM-соединение в 1С?

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

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

Причина проблемы: принцип «Свой-Чужой»

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

Проанализируем типичную ошибку. Если написать так:


СписокСсылок = Новый СписокЗначений;
СписокСсылок.Добавить(НужнаяСсылка);
Запрос = COMБаза.NewObject("Запрос");
Запрос.Текст = "ВЫБРАТЬ * ИЗ Документ.Приказ ГДЕ Ссылка В (&Список)";
Запрос.УстановитьПараметр("Список", СписокСсылок); // ОШИБКА!

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

Решение 1: Создание коллекции через NewObject внешнего соединения

Чтобы внешняя база «признала» список значений своим, его необходимо инициализировать методом NewObject самого COM-соединения. Рассмотрим правильный алгоритм действий по шагам:

  1. Устанавливаем соединение с базой БД2.
  2. Создаем объект СписокЗначений или Массив непосредственно во внешней базе.
  3. Наполняем этот объект данными (примитивными типами).
  4. Передаем созданный объект в параметр запроса.

Посмотрим на пример кода, который решает эту задачу:


// 1. Подключаемся к базе
Коннектор = Новый COMОбъект("V83.COMConnector");
БД2 = Коннектор.Connect("Srvr='ServerName';Ref='BaseName';Usr='Login';Pwd='Password';");

// 2. Создаем список значений ВНУТРИ внешней базы
СписокДляЗапроса = БД2.NewObject("СписокЗначений");

// 3. Заполняем его номерами или другими идентификаторами
Для Каждого СтрокаДокумента Из СписокВыбранных Цикл
    // Добавляем только примитивные типы: Строка, Число, Дата
    СписокДляЗапроса.Добавить(СтрокаДокумента.Номер);
КонецЦикла;

// 4. Выполняем запрос во внешней базе
Запрос = БД2.NewObject("Запрос");
Запрос.Текст = 
    "ВЫБРАТЬ
    |   Приказ.Ссылка
    |ИЗ
    |   Документ.ПриказОПростоях КАК Приказ
    |ГДЕ
    |   Приказ.Номер В (&Список)";

Запрос.УстановитьПараметр("Список", СписокДляЗапроса);
Результат = Запрос.Выполнить().Выгрузить();

Решение 2: Идентификация объектов через GUID

Использование поиска по Номер и Дата — не самый надежный способ, так как номера могут дублироваться или иметь разные префиксы. Самый точный способ сопоставления объектов между базами — использование уникальных идентификаторов (GUID). Выясним, как передать ссылку через её строковое представление.

Рассмотрим алгоритм передачи через UUID:


// В исходной базе получаем УникальныйИдентификатор ссылки
СтрокаGUID = Строка(ДокументСсылка.УникальныйИдентификатор());

// Во внешней базе создаем объект UUID из строки
ВнешнийGUID = БД2.NewObject("UUID", СтрокаGUID);

// Получаем ссылку во внешней базе
СсылкаВБД2 = БД2.Документы.ПриказОПростоях.ПолучитьСсылку(ВнешнийGUID);

// Теперь эту ссылку можно добавить в список, созданный через БД2.NewObject("СписокЗначений")
СписокGUID = БД2.NewObject("СписокЗначений");
СписокGUID.Добавить(СсылкаВБД2);

Этот метод гарантирует, что вы найдете именно тот документ, который нужен, даже если его номер был изменен.

Оптимизация: Передача больших объемов данных

Если вам нужно перенести тысячи документов, использование конструкции В (&Список) может привести к замедлению работы SQL-сервера или ошибке переполнения стека. В таких ситуациях проанализируем использование временных таблиц.

Вместо передачи огромного списка, мы можем создать ТаблицуЗначений через COM, загрузить в неё данные и передать её в запрос как таблицу для помещения во временную таблицу. Однако стоит помнить, что работа с ТаблицейЗначений через COM-интерфейс «построчно» (в цикле) очень медленная. Каждое обращение к свойству или методу через точку — это сетевой вызов.

Рекомендация: старайтесь минимизировать количество вызовов через точку. Если нужно прочитать много данных, лучше выполнить один запрос во внешней базе, выгрузить его в ТаблицуЗначений (метод Выгрузить()), и уже эту таблицу анализировать в локальном коде.

Технические нюансы и «подводные камни»

1. Разрядность систем (32/64 бит)

Если ваш сервер 1С работает в 64-битном режиме, убедитесь, что на сервере зарегистрирован 64-битный COM-коннектор (comcntr.dll). В противном случае вы получите ошибку «Класс не зарегистрирован».

2. Передача типов

При прямом подключении корректно передаются только примитивные типы: Число, Строка, Дата, Булево. Объекты типа Перечисление передать напрямую нельзя. Выход: передавать имя перечисления строкой и в запросе использовать конструкцию ЗНАЧЕНИЕ(Перечисление.Имя.Значение) или искать его во внешней базе через Перечисления[ИмяПеречисления][ИмяЗначения].

3. Завершение соединения

После завершения обмена всегда обнуляйте переменные, содержащие COM-объекты. Это освобождает лицензию и закрывает сеанс на сервере:


БД2 = Неопределено;
Коннектор = Неопределено;

Подведем итоги

Мы выяснили, что основной секрет успешного обмена через прямое подключение заключается в создании объектов коллекций (Списков, Массивов) в контексте той базы, где будет выполняться запрос. Использование метода COM.NewObject("СписокЗначений") позволяет избежать ошибок типизации и корректно передавать параметры в запросы. Применение GUID в качестве идентификатора делает обмен надежным, а минимизация вызовов «через точку» — быстрым.

← На главную