Почему ПолучитьИзВременногоХранилища возвращает Неопределено в отчетах БСП и как это исправить?

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

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

В этой статье мы подробно разберем, почему так происходит, как работают сеансы в 1С и какими способами можно гарантированно передать таблицу значений или массив в отчет, работающий в фоновом режиме.

Причина проблемы: Разделение сеансов

Первым делом проанализируем ситуацию с точки зрения архитектуры платформы «1С:Предприятие 8.3». Когда мы вызываем метод ПоместитьВоВременноеХранилище(Данные, УникальныйИдентификатор), данные привязываются к конкретному сеансу пользователя. Если в качестве второго параметра передается Новый УникальныйИдентификатор(), то время жизни этих данных ограничено текущим серверным вызовом или сеансом (в зависимости от версии платформы и контекста).

Основная сложность при работе с БСП заключается в том, что формирование отчета по умолчанию происходит в фоновом задании. С точки зрения системы, фоновое задание — это отдельный сеанс. Согласно правилам платформы, временное хранилище одного сеанса недоступно из другого. Именно поэтому, когда основной сеанс пользователя поместил таблицу в хранилище, а фоновый сеанс отчета попытался её прочитать по адресу, он получил Неопределено.

Решение 1: Использование идентификатора формы

Рассмотрим стандартный механизм передачи данных между сеансом-родителем и фоновым заданием. Платформа делает исключение для временного хранилища, если оно привязано к идентификатору формы. Выясним, как правильно реализовать этот механизм:

  1. В основном сеансе (в форме отчета) необходимо поместить данные, используя идентификатор текущей формы.
  2. Для корректной передачи в фоновое задание в родительском сеансе сначала следует поместить в хранилище пустое значение, передав идентификатор формы, и получить адрес.
  3. Этот адрес нужно передать в параметры фонового задания.

Однако в БСП процесс запуска фонового задания инкапсулирован внутри системных модулей. Чтобы этот метод сработал, нам нужно убедиться, что адрес хранилища передается в структуру параметров формирования отчета. Посмотрим на пример кода помещения данных:


// В контексте формы отчета
АдресХранилища = ПоместитьВоВременноеХранилище(ТаблицаСДанными, ЭтаФорма.УникальныйИдентификатор);
// Теперь этот АдресХранилища нужно передать в параметры СКД или настройки БСП

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

Решение 2: Передача данных через внешние наборы данных СКД

Если наша задача — передать готовую таблицу значений в отчет СКД, проанализируем возможность использования внешних наборов данных. Это наиболее «чистый» способ с точки зрения разработки. Вместо того чтобы пытаться достать данные из хранилища внутри модуля объекта отчета, мы можем передать их напрямую в процедуру компоновки.

Для этого в схеме компоновки данных (СКД) создается набор данных типа Объект. В модуле объекта отчета, в обработчике ПриКомпоновкеРезультата, мы можем заполнить этот набор данных. Но как получить саму таблицу в модуле объекта, если она была создана в форме?

Рассмотрим вариант передачи через дополнительные свойства или параметры:

  1. Помещаем таблицу в Объект.ДополнительныеСвойства (если это позволяет контекст БСП при передаче объекта на сервер).
  2. Либо используем ПараметрыДанных самой схемы компоновки, если тип параметра позволяет хранить объект (хотя для ТЗ это редко применимо напрямую).

Решение 3: Хранение данных в информационной базе (Регистры или Хранилище настроек)

Проанализируем ситуацию, упомянутую в обсуждении: если используется кластер серверов, временные файлы могут быть недоступны, так как фоновое задание может запуститься на другом рабочем сервере. В таком случае самым надежным способом передачи данных между разными сеансами является использование базы данных.

Выделим шаги для реализации этого метода:

  1. Создадим вспомогательный Регистр сведений (например, «ВременныйБуферДанных») с измерениями Идентификатор (тип УникальныйИдентификатор) и ресурсом Данные (тип ХранилищеЗначения).
  2. Перед запуском отчета в форме сериализуем таблицу значений (или массив) и записываем в регистр.
  3. Передаем только УникальныйИдентификатор записи в качестве параметра отчета.
  4. В модуле объекта отчета (в фоновом задании) считываем данные из регистра по идентификатору, восстанавливаем таблицу и удаляем запись из регистра, чтобы не засорять базу.

Пример кода для записи данных:


КлючСвязи = Новый УникальныйИдентификатор();
ЗаписьРегистра = РегистрыСведений.ВременныйБуферДанных.СоздатьМенеджерЗаписи();
ЗаписьРегистра.Идентификатор = КлючСвязи;
ЗаписьРегистра.Данные = Новый ХранилищеЗначения(ТаблицаExcel, Новый СжатиеДанных(9));
ЗаписьРегистра.Записать();

// Передаем КлючСвязи в параметры отчета

Решение 4: Особенности сериализации Таблицы Значений

Выясним еще одну важную деталь. Иногда ПолучитьИзВременногоХранилища возвращает Неопределено не из-за сеансов, а из-за невозможности сериализовать объект. ТаблицаЗначений успешно передается между контекстами только в том случае, если все типы данных в её колонках поддерживают сериализацию (примитивные типы, ссылки, структуры, массивы).

Если в вашей таблице, прочитанной из Excel, присутствуют специфические COM-объекты или типы, которые нельзя передать на сервер, очистите их или преобразуйте в массив структур перед помещением в хранилище. Рассмотрим пример преобразования:


Функция ТЗвМассивСтруктур(ТаблицаДанных)
    МассивРезультат = Новый Массив;
    Колонки = ТаблицаДанных.Колонки;
    Для Каждого СтрокаТЗ Из ТаблицаДанных Цикл
        СтруктураСтроки = Новый Структура;
        Для Каждого Колонка Из Колонки Цикл
            СтруктураСтроки.Вставить(Колонка.Имя, СтрокаТЗ[Колонка.Имя]);
        КонецЦикла;
        МассивРезультат.Добавить(СтруктураСтроки);
    КонецЦикла;
    Возврат МассивРезультат;
КонецФункции

Подведем итог: Для стабильной работы отчета в БСП при передаче внешних данных лучше всего отказаться от использования временного хранилища с коротким временем жизни. Оптимальным выбором будет либо использование идентификатора формы (при условии правильной передачи адреса в параметры формирования), либо использование промежуточной таблицы в базе данных (регистра сведений), что гарантирует доступность данных в любом узле кластера серверов.

← На главную