При работе с разветвленными информационными системами часто возникает задача консолидации данных. Типичный сценарий: основная деятельность ведется в Управлении торговлей 10.3 (платформа 8.2), а специфический учет — в отраслевом решении на платформе 8.1. Рассмотрим, как объединить данные об остатках из этих баз, используя технологию COM-соединения, и внедрить этот функционал в существующий Универсальный отчет, не переписывая его архитектуру полностью.
Представим ситуацию: нам необходимо дополнить отчет «Анализ доступности товаров на складах» в базе 8.2 данными по остаткам из базы 8.1. Основная сложность заключается в том, что справочники номенклатуры в базах не идентичны (наименования могут различаться), а сопоставление происходит по коду, который в одной базе хранится в карточке товара, а в другой — может быть зафиксирован в регистре сведений НоменклатураКонтрагентов.
Разберем поэтапно, как реализовать этот механизм, обеспечив максимальную производительность и корректность передачи данных.
Для начала нам необходимо подключиться к внешней базе. Важно использовать объект V81.COMConnector, так как он работает быстрее, чем полноценное приложение Application, поскольку не требует инициализации графического интерфейса.
Проанализируем процесс получения данных из внешней базы:
// Инициализация соединения
Попытка
COMСоединение = Новый COMОбъект("V81.COMConnector");
ПараметрыСвязи = "Srvr='ServerName';Ref='BaseName';Usr='Login';Pwd='Password';";
БД = COMСоединение.Connect(ПараметрыСвязи);
Исключение
Сообщить("Не удалось установить соединение: " + ОписаниеОшибки());
Возврат;
КонецПопытки;
// Формирование запроса во внешней базе
ЗапросВнешний = БД.NewObject("Запрос");
ЗапросВнешний.Текст =
"ВЫБРАТЬ
| ТоварыНаСкладахОстатки.Номенклатура.Код КАК Код,
| ТоварыНаСкладахОстатки.КоличествоОстаток КАК Остаток81
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки КАК ТоварыНаСкладахОстатки";
ТабВнешняя = ЗапросВнешний.Выполнить().Выгрузить();
Важный момент: полученный объект ТабВнешняя является COM-объектом. Мы не можем напрямую передать его в запрос текущей базы (в качестве параметра временной таблицы), так как менеджер временных таблиц 8.2 «не понимает» структуру объектов базы 8.1.
Чтобы использовать данные из внешней базы в нашем отчете, необходимо «приземлить» их в локальную таблицу значений (ТЗ). Рассмотрим наиболее эффективный способ — ручной перебор строк. Метод ЗначениеВСтрокуВнутр часто дает сбои при переходе между версиями платформ 8.1 и 8.2 из-за различий в сериализации объектов.
Создадим локальную таблицу и заполним ее:
ЛокальнаяТЗ = Новый ТаблицаЗначений;
ЛокальнаяТЗ.Колонки.Добавить("Код", Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(20)));
ЛокальнаяТЗ.Колонки.Добавить("Остаток81", Новый ОписаниеТипов("Число", , Новый КвалификаторыЧисла(15, 3)));
// Переносим данные
Для Каждого СтрокаВнешняя Из ТабВнешняя Цикл
НоваяСтрока = ЛокальнаяТЗ.Добавить();
НоваяСтрока.Код = СтрокаВнешняя.Код;
НоваяСтрока.Остаток81 = СтрокаВнешняя.Остаток81;
КонецЦикла;
Такой подход гарантирует, что все типы данных будут приведены к примитивным (строки, числа), которые корректно обрабатываются в любой версии платформы.
Теперь, когда у нас есть ЛокальнаяТЗ, мы можем передать ее в запрос Универсального отчета. Универсальный отчет в УТ 10.3 строится на базе объекта ПостроительЗапроса. Нам нужно модифицировать текст запроса так, чтобы он соединялся с нашей временной таблицей.
Проанализируем, как поместить данные во временную таблицу (МВТ):
МенеджерВТ = Новый МенеджерВременныхТаблиц;
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МенеджерВТ;
// Помещаем локальную ТЗ во временную таблицу
Запрос.Текст =
"ВЫБРАТЬ * ПОМЕСТИТЬ ВТ_ОстаткиВнешние ИЗ &ВнешниеДанные КАК ВнешниеДанные";
Запрос.УстановитьПараметр("ВнешниеДанные", ЛокальнаяТЗ);
Запрос.Выполнить();
Теперь временная таблица ВТ_ОстаткиВнешние доступна в рамках сессии менеджера временных таблиц и может быть использована в основном запросе отчета.
Универсальный отчет хранит основной текст запроса в модуле объекта (обычно в процедуре УстановитьНачальныеНастройки или СформироватьОтчет). Чтобы добавить остатки из 8.1, выполним следующие действия:
ТекстЗапроса присваивается значение.ЛЕВОЕ СОЕДИНЕНИЕ с нашей временной таблицей по полю «Код».НоменклатураКонтрагентов или напрямую в справочнике, запрос будет выглядеть примерно так:
ТекстЗапроса =
"ВЫБРАТЬ
| ОсновнойЗапрос.Номенклатура КАК Номенклатура,
| ОсновнойЗапрос.КоличествоОстаток КАК Остаток82,
| ЕСТЬNULL(ВТ_ОстаткиВнешние.Остаток81, 0) КАК Остаток81
|ИЗ
| (&ТекстОсновногоЗапроса) КАК ОсновнойЗапрос
| ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ОстаткиВнешние КАК ВТ_ОстаткиВнешние
| ПО ОсновнойЗапрос.Номенклатура.Код = ВТ_ОстаткиВнешние.Код";
Работа через COM — это всегда нагрузка на сеть и память. Разберем, как сделать работу отчета быстрее:
1. Фильтрация на стороне источника. Не стоит выгружать все остатки из базы 8.1. Проанализируем настройки отбора в 8.2, соберем массив кодов номенклатуры, которая попала в отчет, и передадим этот массив в COM-запрос как параметр. Это в разы сократит объем передаваемого трафика.
2. Использование уникальных идентификаторов (GUID). Если есть возможность прописать UID из 8.1 в дополнительный реквизит номенклатуры в 8.2, это будет самым надежным способом связи. Сопоставление по строковому коду может быть нестабильным (например, из-за префиксов).
3. Кэширование соединения. Создание COM-объекта занимает 2-5 секунд. Если пользователь формирует отчет несколько раз подряд с разными настройками, целесообразно хранить открытое соединение в переменной модуля или в параметрах сеанса (если это допустимо архитектурой).
Для реализации задачи мы рассмотрели использование V81.COMConnector, выяснили необходимость ручного копирования данных в локальную таблицу значений для преодоления несовместимости типов, и разобрали механизм внедрения внешних данных в ПостроительЗапроса через временные таблицы. Этот метод позволяет расширить функционал стандартных отчетов 1С 8.2, сохраняя их привычный интерфейс и возможности группировок.