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