При интеграции двух информационных баз 1С с помощью внешнего соединения (COMConnector) разработчики часто сталкиваются с задачей передачи данных из текущей конфигурации в запрос удаленной базы. Попытка передать выгрузку запроса или локальную таблицу значений напрямую в качестве параметра удаленного запроса приводит к ошибкам: «Неверные параметры» или «Тип не может быть выбран в запросе».
Разберем причины возникновения этих ошибок и пошагово рассмотрим способы их устранения, а также изучим эффективные альтернативы построчному заполнению данных через COM.
Проанализируем две основные проблемы, возникающие при передаче параметров во внешний запрос:
ПОМЕСТИТЬ ВТ_Имя ИЗ &ВнешнийИсточник требует обязательного явного указания типов данных для всех колонок таблицы. Если колонка добавлена без описания типов, платформа не может создать временную таблицу в СУБД и выдает ошибку о невозможности выбора типа.Разберем правильный порядок действий для формирования таблицы значений во внешней базе с последующей передачей в запрос.
Для создания описания типов во внешнем соединении используется вызов метода NewObject внешнего подключения. Обратите внимание: синтаксис Открыта.ОписаниеТипов("Число") некорректен, так как глобальный контекст удаленной базы недоступен напрямую через обращение к свойствам подключения. Имя типа объекта всегда передается строкой в метод NewObject.
Посмотрим на пример правильного создания структуры таблицы и колонок с примитивными и ссылочными типами данных:
v8 = Новый COMObject("V83.COMConnector");
Открыта = v8.Connect("Srvr=""server"";Ref=""Base2"";Usr=""Администратор"";Pwd=""Пароль"";");
// 1. Создаем таблицу значений во внешней базе
ВнешнийИсточник = Открыта.NewObject("ТаблицаЗначений");
// 2. Создаем описатели типов для колонок
КвалификаторЧисла = Открыта.NewObject("КвалификаторыЧисла", 15, 2);
ТипСумма = Открыта.NewObject("ОписаниеТипов", "Число", , КвалификаторЧисла);
КвалификаторДаты = Открыта.NewObject("КвалификаторыДаты", Открыта.ЧастиДаты.Дата);
ТипПериод = Открыта.NewObject("ОписаниеТипов", "Дата", , , КвалификаторДаты);
ТипНоменклатурнаяГруппа = Открыта.NewObject("ОписаниеТипов", "СправочникСсылка.НоменклатурнаяГруппа");
ТипВидДеятельности = Открыта.NewObject("ОписаниеТипов", "СправочникСсылка.ВидыДеятельности");
// 3. Добавляем типизированные колонки
ВнешнийИсточник.Колонки.Добавить("Сумма", ТипСумма);
ВнешнийИсточник.Колонки.Добавить("Период", ТипПериод);
ВнешнийИсточник.Колонки.Добавить("НоменклатурнаяГруппа", ТипНоменклатурнаяГруппа);
ВнешнийИсточник.Колонки.Добавить("ВидДеятельности", ТипВидДеятельности);
После создания структуры необходимо заполнить строки. Если реквизиты являются ссылочными, их нельзя просто присвоить из локальной выборки. Ссылку необходимо получить в контексте удаленной базы (например, методом НайтиПоНаименованию, НайтиПоКоду или ПолучитьСсылку по уникальному идентификатору).
Рассмотрим заполнение строк таблицы:
Выборка = ЗапросПроценты.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
НоваяСтрока = ВнешнийИсточник.Добавить();
НоваяСтрока.Сумма = Выборка.Сумма;
НоваяСтрока.Период = Выборка.Период;
// Получение ссылок в контексте внешней ИБ
НоваяСтрока.НоменклатурнаяГруппа = Открыта.Справочники.НоменклатурнаяГруппа.НайтиПоНаименованию(Выборка.НоменклатурнаяГруппа);
НоваяСтрока.ВидДеятельности = Открыта.Справочники.ВидыДеятельности.НайтиПоНаименованию(Выборка.ВидДеятельности);
КонецЦикла;
// 4. Передача подготовленной таблицы в запрос
Query = Открыта.NewObject("Запрос");
Query.Текст =
"ВЫБРАТЬ
| ТЗ.Сумма КАК Сумма,
| ТЗ.Период КАК Период,
| ТЗ.НоменклатурнаяГруппа КАК НоменклатурнаяГруппа,
| ТЗ.ВидДеятельности КАК ВидДеятельности
|ПОМЕСТИТЬ ВТ_05ПРОЦЕНТ
|ИЗ
| &ВнешнийИсточник КАК ТЗ";
Query.УстановитьПараметр("ВнешнийИсточник", ВнешнийИсточник);
РезультатЗапроса = Query.Выполнить();
Построчный перебор и установка свойств COM-объекта в цикле вызывают существенные накладные расходы из-за межпроцессного взаимодействия (COM Marshaling). Если таблица содержит сотни или тысячи строк, а также выполняет поиск ссылок в цикле, выполнение может затянуться на длительное время.
Разберем быстрые альтернативные способы пакетной передачи таблицы значений, если она состоит из простых типов данных.
Если исходная таблица содержит примитивные типы (числа, строки, даты), наиболее надежным и быстрым вариантом является выгрузка через XML. При этом типы данных колонок переносятся автоматически:
// На стороне текущей базы:
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();
СериализаторXDTO.ЗаписатьXML(ЗаписьXML, ЛокальнаяТЗ);
СтрокаXML = ЗаписьXML.Закрыть();
// На стороне удаленной базы через COM:
ЧтениеXML = Открыта.NewObject("ЧтениеXML");
ЧтениеXML.УстановитьСтроку(СтрокаXML);
ВнешнийИсточник = Открыта.СериализаторXDTO.ПрочитатьXML(ЧтениеXML);
// Полученная таблица уже типизирована и готова к передаче в запрос
Query.УстановитьПараметр("ВнешнийИсточник", ВнешнийИсточник);
Для простых типизированных таблиц можно использовать платформенные функции сериализации во внутренний формат:
СтрокаДанных = ЗначениеВСтрокуВнутр(ЛокальнаяТЗ);
ВнешнийИсточник = Открыта.ЗначениеИзСтрокиВнутр(СтрокаДанных);
Query.УстановитьПараметр("ВнешнийИсточник", ВнешнийИсточник);
При проектировании обмена через внешнее соединение важно учитывать системные ограничения технологии:
Открыта.NewObject("Массив")) и условие в запросе ГДЕ Поле В (&МассивПараметров). Для массивов не требуется явное описание типов.comcntr.dll чувствительна к битности приложений (32 и 64 бита). При несовпадении разрядности клиента и сервера необходимо настраивать запуск через службы компонентов Windows (COM+ Application).