При интеграции двух информационных баз 1С часто возникает задача передачи данных из одной базы в другую для выполнения сложных запросов с соединениями. Одной из наиболее трудоемких операций является передача объекта ТаблицаЗначений (ТЗ) в качестве параметра запроса через COM-соединение. Многие разработчики сталкиваются с тем, что запрос «не видит» таблицу или выдает ошибки типов. В этой статье мы подробно разберем, как правильно подготовить и передать таблицу значений, чтобы использовать её во временных таблицах внешнего запроса.
Рассмотрим стандартную ситуацию: у нас есть «первая» база (текущая) и «вторая» база, к которой мы подключаемся через COM. Мы создаем объект Запрос во внешней базе и пытаемся передать в его параметры таблицу значений, сформированную локально. Основная причина неудачи кроется в том, что объекты ТаблицаЗначений и ОписаниеТипов являются сложными типами. Когда мы передаем локальную таблицу во внешнюю базу, COM-интерфейс не всегда может корректно сопоставить типы данных, особенно если колонки таблицы не типизированы жестко.
Проанализируем типичную ошибку. Если просто создать колонку методом Добавить("ИмяКолонки"), 1С присваивает ей пустой тип или тип Произвольный. При попытке поместить такую таблицу во временную таблицу (ПОМЕСТИТЬ ВТ) менеджер временных таблиц внешней базы не может определить структуру полей БД, что приводит к краху запроса.
Самый надежный способ передать таблицу значений через COM — это создать саму таблицу и все её вспомогательные объекты (типы, квалификаторы) непосредственно в контексте внешней базы. Выясним, как это сделать по шагам.
Во-первых, нам необходимо инициализировать соединение и создать объект таблицы значений именно во внешней базе. Во-вторых, для каждой колонки мы должны явно задать ОписаниеТипов, используя конструкторы внешней базы.
Рассмотрим пример кода, который решает эту задачу:
// Предположим, V82 — это установленное COM-соединение с внешней базой
// 1. Создаем объект ТаблицаЗначений во внешней базе
ТБЗ_Внешняя = V82.NewObject("ТаблицаЗначений");
// 2. Создаем квалификаторы для числовых данных
// Важно использовать V82.NewObject, чтобы объект принадлежал внешней базе
КвалификаторЧисла = V82.NewObject("КвалификаторыЧисла", 15, 2);
// 3. Формируем ОписаниеТипов во внешней базе
ДоступныеТипыЧисло = V82.NewObject("ОписаниеТипов", "Число", КвалификаторЧисла);
ДоступныеТипыСтрока = V82.NewObject("ОписаниеТипов", "Строка", V82.NewObject("КвалификаторыСтроки", 20));
// 4. Добавляем колонки с явным указанием типов
ТБЗ_Внешняя.Колонки.Добавить("КодНом", ДоступныеТипыСтрока);
ТБЗ_Внешняя.Колонки.Добавить("Количество", ДоступныеТипыЧисло);
// 5. Заполняем таблицу данными из нашей локальной ТЗ
Для Каждого СтрокаЛок Из ЛокальнаяТЗ Цикл
НоваяСтрока = ТБЗ_Внешняя.Добавить();
НоваяСтрока.КодНом = СтрокаЛок.КодНоменклатуры;
НоваяСтрока.Количество = СтрокаЛок.Количество;
КонецЦикла;
// 6. Теперь таблицу можно передать в запрос
Запрос = V82.NewObject("Запрос");
Запрос.Текст =
"ВЫБРАТЬ * ПОМЕСТИТЬ ВТ_Данные ИЗ &ВнешняяТЗ КАК ВнешняяТЗ;
|ВЫБРАТЬ ВТ.КодНом, Спр.Ссылка ИЗ ВТ_Данные КАК ВТ
|ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Спр ПО ВТ.КодНом = Спр.Код";
Запрос.УстановитьПараметр("ВнешняяТЗ", ТБЗ_Внешняя);
Результат = Запрос.Выполнить().Выгрузить();
Обратите внимание: использование КвалификаторыЧисла и других квалификаторов критично для версий платформы 8.3.13 и выше. В этих версиях механизм запросов стал более строго проверять соответствие типов во временных таблицах.
Существует альтернативный подход, который иногда называют «хаком», но он может быть полезен при идентичных конфигурациях. Речь идет об использовании функций ЗначениеВСтрокуВнутр и ЗначениеИзСтрокиВнутр. Посмотрим на этот метод подробнее:
Суть заключается в том, что мы преобразуем нашу локальную таблицу в специальный строковый формат 1С, передаем эту строку через COM как обычный текст, а во внешней базе выполняем обратное преобразование. Однако важно помнить: метод ЗначениеИзСтрокиВнутр должен быть вызван именно объектом внешней базы.
// Способ с использованием внутренней сериализации (устаревший, но рабочий)
СтрокаТЗ = ЗначениеВСтрокуВнутр(ЛокальнаяТЗ);
ТЗ_ДляЗапроса = V82.ЗначениеИзСтрокиВнутр(СтрокаТЗ);
Запрос.УстановитьПараметр("ТБЗ", ТЗ_ДляЗапроса);
Внимание: Этот метод имеет ряд ограничений. Во-первых, он официально считается устаревшим со времен версии 7.7. Во-вторых, он корректно работает только для простых типов данных (числа, строки, даты). Если в вашей таблице есть ссылки на объекты (например, СправочникСсылка.Номенклатура), то при десериализации во внешней базе эти ссылки превратятся в «битые», так как ГУИДы (GUID) объектов в разных базах, скорее всего, различаются.
Проанализируем ситуацию, когда запрос состоит из нескольких пакетов. Для того чтобы внешняя база успешно обработала ПОМЕСТИТЬ, настоятельно рекомендуется явно инициализировать МенеджерВременныхТаблиц. Разберем, как это реализовать через COM:
МВТ = V82.NewObject("МенеджерВременныхТаблиц");.Запрос.МенеджерВременныхТаблиц = МВТ;.Это гарантирует, что таблица будет «жить» в памяти внешней базы на протяжении всего времени работы с объектом МВТ, и вы сможете обращаться к ней в последующих запросах через это же соединение. Для интерактивной работы с такими выборками подойдёт консоль запросов к двум базам с общим менеджером временных таблиц.
Выясним причину медленной работы COM-соединений. Когда мы в цикле вызываем ТБЗ_Внешняя.Добавить() и заполняем поля, каждое обращение — это сетевой вызов (RPC) между процессами. Если в таблице 10 000 строк, это превращается в 20 000+ вызовов, что может занять минуты.
Для оптимизации рекомендуется использовать следующие подходы:
СериализаторXDTO, передать строку во внешнюю базу и там восстановить объект. Это работает значительно быстрее построчного заполнения.Рассмотрим ситуацию, когда в таблице нужно передать не просто коды или артикулы, а именно ссылки. Как мы уже выяснили, прямая передача ссылки из одной базы в другую бесполезна. Правильный алгоритм действий будет следующим:
Подведем итог. Чтобы успешно передать таблицу значений в запрос через COM-соединение, необходимо обеспечить идентичность контекста. Создавайте таблицу и её типы (ОписаниеТипов) средствами внешнего соединения. Если данных много — используйте XML-сериализацию. И всегда помните о строгой типизации колонок, особенно в актуальных версиях платформы 1С:Предприятие 8.3. Для выполнения произвольных запросов во внешней информационной базе также можно использовать обработку для выполнения запросов и алгоритмов через COM-подключение.