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