Как передать данные из заполненной табличной части отчета в СКД при фоновом формировании результата

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке сложных отчетов на базе Системы компоновки данных (СКД) часто возникает ситуация, когда источником данных служит не прямой запрос к базе, а предварительно обработанная таблица. Нередко программисты реализуют это через табличную часть (ТЧ) самого объекта отчета, которую пользователь заполняет на форме (например, загружая данные из внешнего API или Excel). Однако при нажатии кнопки «Сформировать» разработчики сталкиваются с неприятным сюрпризом: внутри обработчика ПриКомпоновкеРезультата табличная часть оказывается пустой, хотя на форме данные отображаются корректно.

В этой статье мы подробно разберем, почему так происходит, проанализируем внутренние механизмы платформы и БСП, а также рассмотрим надежные способы решения этой задачи.

Выясним причину: почему данные «исчезают»?

Рассмотрим ситуацию глубже. В современных конфигурациях, построенных на Библиотеке стандартных подсистем (БСП), отчеты по умолчанию формируются в фоновом задании. Это делается для того, чтобы интерфейс пользователя не «зависал» во время длительных вычислений.

Проанализируем цепочку событий:

  1. Пользователь открывает форму отчета, заполняет табличную часть Объект.ДанныеДляОтчета. Эти данные живут в памяти текущего сеанса в конкретном экземпляре объекта формы.
  2. При нажатии кнопки «Сформировать» БСП запускает фоновое задание на сервере.
  3. Важный момент: фоновое задание выполняется в отдельном сеансе. Для его работы платформа создает новый экземпляр объекта отчета на основании метаданных.
  4. Этот новый экземпляр ничего не знает о том объекте, который открыт у пользователя на экране. Его табличные части пусты по умолчанию.

Именно поэтому в методе ПриКомпоновкеРезультата, который выполняется уже в контексте фонового задания, ваша таблица будет пустой. Обращение к ЭтотОбъект.ДанныеДляОтчета возвращает пустую коллекцию нового экземпляра.

Способ 1. Использование временного хранилища и дополнительных свойств настроек

Это наиболее правильный и «чистый» архитектурный подход. Нам нужно передать данные из клиентского сеанса в фоновый. Поскольку передать объект целиком невозможно, мы воспользуемся Временным хранилищем и механизмом Дополнительных свойств компоновщика настроек, который автоматически сериализуется и передается в фоное задание.

Разберем реализацию по шагам.

Шаг 1. Подготовка данных на форме. В модуле формы отчета (или в команде формирования) нам нужно выгрузить ТЧ в таблицу значений и поместить её в хранилище.


&НаСервере
Процедура ПодготовитьДанныеПередФормированием()
    
    // Выгружаем ТЧ в обычную Таблицу Значений
    ТаблицаДанных = Отчет.ДанныеДляОтчета.Выгрузить();
    
    // Помещаем во временное хранилище. 
    // Обязательно привязываем к УникальномуИдентификатору формы, 
    // чтобы данные не удалились преждевременно.
    АдресХранилища = ПоместитьВоВременноеХранилище(ТаблицаДанных, ЭтаФорма.УникальныйИдентификатор);
    
    // Передаем адрес в настройки компоновщика. 
    // ДополнительныеСвойства будут доступны в фоновом задании.
    Отчет.КомпоновщикНастроек.Настройки.ДополнительныеСвойства.Вставить("АдресДанныхДляСКД", АдресХранилища);
    
КонецПроцедуры

Шаг 2. Получение данных в модуле объекта. Теперь в модуле объекта отчета, внутри стандартного события ПриКомпоновкеРезультата, мы извлечем эти данные.


Процедура ПриКомпоновкеРезультата(ДанныеРасшифровки, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Ложь; // Берем управление в свои руки
    
    // Пытаемся получить адрес из дополнительных свойств
    АдресДанных = Неопределено;
    Если КомпоновщикНастроек.Настройки.ДополнительныеСвойства.Свойство("АдресДанныхДляСКД", АдресДанных) Тогда
        
        // Получаем таблицу из хранилища
        ТаблицаДляСКД = ПолучитьИзВременногоХранилища(АдресДанных);
        
        Если ТипЗнч(ТаблицаДляСКД) = Тип("ТаблицаЗначений") Тогда
            
            // Формируем структуру внешних наборов данных
            ВнешниеНаборыДанных = Новый Структура;
            ВнешниеНаборыДанных.Вставить("ИмяВашегоНабораДанныхВ_СКД", ТаблицаДляСКД);
            
            // Запускаем компоновку
            КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
            МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, КомпоновщикНастроек.ПолучитьНастройки(), ДанныеРасшифровки);
            
            ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
            ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, ВнешниеНаборыДанных, ДанныеРасшифровки);
            
            ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
            ПроцессорВывода.УстановитьДокумент(Результат);
            ПроцессорВывода.Вывести(ПроцессорКомпоновки);
            
        КонецЕсли;
        
    КонецЕсли;

КонецПроцедуры

Способ 2. Передача через скрытый параметр СКД

Если по каким-то причинам использование ДополнительныеСвойства вам не подходит, можно рассмотреть вариант со скрытым параметром самой схемы компоновки. Рассмотрим этот пример.

  1. В схеме СКД создадим параметр с именем АдресВременногоХранилища (тип Строка).
  2. Снимем флаг «Включать в доступные поля», чтобы пользователь не видел этот параметр в настройках.
  3. На форме перед формированием записываем адрес хранилища в этот параметр:

ПараметрСКД = Отчет.КомпоновщикНастроек.Настройки.ПараметрыДанных.Элементы.Найти("АдресВременногоХранилища");
Если ПараметрСКД <> Неопределено Тогда
    ПараметрСКД.Значение = АдресХранилища;
    ПараметрСКД.Использование = Истина;
КонецЕсли;

В методе ПриКомпоновкеРезультата мы аналогично считываем значение этого параметра из КомпоновщикНастроек.Настройки.ПараметрыДанных и получаем таблицу. Этот способ гарантирует, что адрес «уедет» в фоновое задание даже при использовании специфических механизмов БСП по сериализации настроек.

Почему не стоит использовать константы или параметры сеанса?

Рассмотрим ситуацию, описанную в некоторых сообщениях на форумах, где предлагают записывать таблицу в Константу с типом ХранилищеЗначения. Мы настоятельно не рекомендуем этот метод по следующим причинам:

Использование Параметров сеанса также невозможно в данном контексте, так как фоновое задание запускается в новом сеансе, где ваши параметры сеанса будут не инициализированы.

Проанализируем работу с Менеджером временных таблиц (МВТ)

Иногда данных настолько много, что передавать их как ТаблицуЗначений во внешний набор данных становится неэффективно. В этом случае проанализируем возможность использования МенеджераВременныхТаблиц.

Хотя МенеджерВременныхТаблиц нельзя напрямую передать между сеансами, мы можем:

  1. Передать таблицу через Временное хранилище (как описано выше).
  2. Внутри фонового задания (в модуле объекта) создать новый Запрос, инициализировать в нем новый МенеджерВременныхТаблиц.
  3. Загрузить переданную таблицу во временную таблицу внутри этого менеджера.
  4. Установить этот менеджер в ПроцессорКомпоновкиДанных.

Это позволит вам использовать переданные данные внутри сложных запросов самой СКД, соединяя их с реальными таблицами базы данных максимально быстро.

Резюме

Подведем итог нашему исследованию. Если ваш отчет на СКД использует данные из табличной части объекта, помните о специфике фонового формирования:

  1. Данные ТЧ на форме не попадают в фоновое задание автоматически.
  2. Самый надежный способ передачи — поместить ТЗ во временное хранилище и передать строковый адрес через ДополнительныеСвойства настроек компоновщика.
  3. Всегда используйте УникальныйИдентификатор формы при помещении в хранилище, чтобы обеспечить доступность данных на время жизни формы.

Следуя этим правилам, вы обеспечите стабильную работу отчетов в любых современных конфигурациях на платформе «1С:Предприятие 8.3».

← На главную