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

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

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

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

Разбор основной проблемы: Контекст объектов

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

Когда мы пишем МассивОпераций = Новый Массив, объект создается в оперативной памяти текущей базы. Даже если мы добавим в него ссылки, полученные через БазаУПП, сам контейнер (массив) остается "чужим" для внешней базы. Внешний экземпляр 1С не может корректно обработать тип данных Массив, принадлежащий другому процессу.

Решение: Создавать массив необходимо непосредственно в контексте внешней базы. Рассмотрим, как это сделать правильно:


// Неправильно:
// МассивОпераций = Новый Массив; 

// Правильно: создаем объект через COM-соединение
МассивОпераций = БазаУПП.NewObject("Массив");

МассивОпераций.Добавить(БазаУПП.Перечисления.ВидыОперацийСДивидендами.ВыплатаПочтой);
МассивОпераций.Добавить(БазаУПП.Перечисления.ВидыОперацийСДивидендами.ВыплатаЧерезБанк);

Использование метода NewObject (или англоязычного аналога НовыйОбъект) позволяет создать структуру данных, которую внешняя база будет воспринимать как "свою". Это универсальное правило для всех коллекций: ТаблицаЗначений, СписокЗначений, Структура и т.д.

Работа с перечислениями внутри текста запроса

Зачастую передачу массива параметров можно и вовсе избежать, что сделает код чище, а выполнение запроса — быстрее. Если список значений перечисления фиксирован и известен заранее, лучше всего использовать конструкцию ЗНАЧЕНИЕ() непосредственно в теле запроса.

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


ЗапросУПП = БазаУПП.NewObject("Запрос");  

ЗапросУПП.Текст = 
"ВЫБРАТЬ
|	РегистрацияОперацийСДивидендами.Ссылка КАК Ссылка,
|	РегистрацияОперацийСДивидендами.Номер КАК Номер,
|	РегистрацияОперацийСДивидендами.Дата КАК Дата
|ИЗ
|	Документ.РегистрацияОперацийСДивидендами КАК РегистрацияОперацийСДивидендами
|ГДЕ
|	РегистрацияОперацийСДивидендами.ВидОперации В (
|		ЗНАЧЕНИЕ(Перечисление.ВидыОперацийСДивидендами.ВыплатаПочтой), 
|		ЗНАЧЕНИЕ(Перечисление.ВидыОперацийСДивидендами.ВыплатаЧерезБанк)
|	)";

Важный момент: при использовании ЗНАЧЕНИЕ() в запросе, который выполняется через COM, вы должны указывать имена метаданных именно так, как они называются во внешней базе. Обратите внимание на возможные опечатки в конфигурации поставщика (например, ВыплатаЧерезЗапрплату вместо Зарплату) — COM-соединение крайне чувствительно к точности имен.

Получение строковых представлений и имен перечислений

Иногда после выполнения запроса нам нужно получить не саму ссылку на перечисление, а его текстовое представление или программное имя для дальнейшего сопоставления в логике 1С:ЗУП. Рассмотрим два подхода.

  1. Использование функции ПРЕДСТАВЛЕНИЕ: В тексте запроса можно сразу получить читаемое название.
    
    ЗапросУПП.Текст = "ВЫБРАТЬ ПРЕДСТАВЛЕНИЕ(ВидОперации) КАК ВидОперацииТекст ...";
    
    Однако помните, что представление зависит от языка интерфейса и может измениться.
  2. Получение имени значения через метаданные: Если вам нужно именно программное имя (идентификатор), лучше обратиться к метаданным внешней базы. ИмяЗначения = БазаУПП.Метаданные.Перечисления.ВидыОперацийСДивидендами.ЗначенияПеречисления.Индекс(Значение).Имя;

Технические нюансы производительности COM-соединений

Выясним причину, по которой работа через COM может замедляться или приводить к падению системы. Каждый вызов метода через точку от COMОбъекта (например, БазаУПП.Справочники...) — это так называемый "round-trip" или сетевой пакет между процессами. Если таких вызовов тысячи, время выполнения возрастет лавинообразно.

Для оптимизации рекомендуем придерживаться следующих правил:

Завершение работы и очистка памяти

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


ЗапросУПП = Неопределено;
БазаУПП = Неопределено;

Это гарантирует своевременное закрытие сеанса во внешней базе и стабильную работу обоих приложений.

← На главную