При организации интеграции между двумя базами 1С (например, при загрузке данных из УПП в ЗУП) программисты часто выбирают механизм COM-соединения. Несмотря на то что этот метод считается классическим, он таит в себе множество нюансов, связанных с разграничением контекстов выполнения кода. Одной из наиболее распространенных проблем является передача параметров в запрос, выполняемый во внешней базе, особенно если речь идет о массивах или ссылках на перечисления.
В этой статье мы подробно разберем, почему возникают ошибки при работе с COMОбъектами, как правильно инициализировать коллекции во внешнем соединении и каким образом эффективно работать с перечислениями в текстах запросов.
Рассмотрим ситуацию: вы создаете массив в текущей базе, заполняете его значениями, полученными из внешней базы, и пытаетесь передать этот массив в качестве параметра запроса ЗапросУПП.УстановитьПараметр(). В этот момент система выдает ошибку. Проанализируем причину.
Когда мы пишем МассивОпераций = Новый Массив, объект создается в оперативной памяти текущей базы. Даже если мы добавим в него ссылки, полученные через БазаУПП, сам контейнер (массив) остается "чужим" для внешней базы. Внешний экземпляр 1С не может корректно обработать тип данных Массив, принадлежащий другому процессу.
Решение: Создавать массив необходимо непосредственно в контексте внешней базы. Рассмотрим, как это сделать правильно:
// Неправильно:
// МассивОпераций = Новый Массив;
// Правильно: создаем объект через COM-соединение
МассивОпераций = БазаУПП.NewObject("Массив");
МассивОпераций.Добавить(БазаУПП.Перечисления.ВидыОперацийСДивидендами.ВыплатаПочтой);
МассивОпераций.Добавить(БазаУПП.Перечисления.ВидыОперацийСДивидендами.ВыплатаЧерезБанк);
Использование метода NewObject (или англоязычного аналога НовыйОбъект) позволяет создать структуру данных, которую внешняя база будет воспринимать как "свою". Это универсальное правило для всех коллекций: ТаблицаЗначений, СписокЗначений, Структура и т.д.
Зачастую передачу массива параметров можно и вовсе избежать, что сделает код чище, а выполнение запроса — быстрее. Если список значений перечисления фиксирован и известен заранее, лучше всего использовать конструкцию ЗНАЧЕНИЕ() непосредственно в теле запроса.
Проанализируем пример оптимизированного запроса, где условия по видам операций жестко прописаны в коде. Это избавляет нас от необходимости создавать объекты через COM и передавать их через границу процессов:
ЗапросУПП = БазаУПП.NewObject("Запрос");
ЗапросУПП.Текст =
"ВЫБРАТЬ
| РегистрацияОперацийСДивидендами.Ссылка КАК Ссылка,
| РегистрацияОперацийСДивидендами.Номер КАК Номер,
| РегистрацияОперацийСДивидендами.Дата КАК Дата
|ИЗ
| Документ.РегистрацияОперацийСДивидендами КАК РегистрацияОперацийСДивидендами
|ГДЕ
| РегистрацияОперацийСДивидендами.ВидОперации В (
| ЗНАЧЕНИЕ(Перечисление.ВидыОперацийСДивидендами.ВыплатаПочтой),
| ЗНАЧЕНИЕ(Перечисление.ВидыОперацийСДивидендами.ВыплатаЧерезБанк)
| )";
Важный момент: при использовании ЗНАЧЕНИЕ() в запросе, который выполняется через COM, вы должны указывать имена метаданных именно так, как они называются во внешней базе. Обратите внимание на возможные опечатки в конфигурации поставщика (например, ВыплатаЧерезЗапрплату вместо Зарплату) — COM-соединение крайне чувствительно к точности имен.
Иногда после выполнения запроса нам нужно получить не саму ссылку на перечисление, а его текстовое представление или программное имя для дальнейшего сопоставления в логике 1С:ЗУП. Рассмотрим два подхода.
ЗапросУПП.Текст = "ВЫБРАТЬ ПРЕДСТАВЛЕНИЕ(ВидОперации) КАК ВидОперацииТекст ...";
ИмяЗначения = БазаУПП.Метаданные.Перечисления.ВидыОперацийСДивидендами.ЗначенияПеречисления.Индекс(Значение).Имя;
Выясним причину, по которой работа через COM может замедляться или приводить к падению системы. Каждый вызов метода через точку от COMОбъекта (например, БазаУПП.Справочники...) — это так называемый "round-trip" или сетевой пакет между процессами. Если таких вызовов тысячи, время выполнения возрастет лавинообразно.
Для оптимизации рекомендуем придерживаться следующих правил:
Выгрузить() в таблицу значений, вместо того чтобы перебирать ссылки в цикле.V83.Application, так как не инициализирует графическую оболочку и лишние клиентские модули.comcntr.dll зарегистрирована корректно. Часто требуется настройка COM+ Application в Windows (Component Services) для создания 32-битной "обертки" для COM-соединения.Важно помнить, что COM-соединение держит сессию в базе-источнике активной до тех пор, пока объект в памяти. Это занимает лицензию и потребляет ресурсы сервера. После завершения всех операций обязательно обнуляйте переменную соединения:
ЗапросУПП = Неопределено;
БазаУПП = Неопределено;
Это гарантирует своевременное закрытие сеанса во внешней базе и стабильную работу обоих приложений.