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

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

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

Выясним причину, почему возникает ошибка при наивной реализации:


// Ошибочный вариант сохранения:
ТабДок = ЭлементыФормы.ПолеТабличногоДокумента;
Хранилище = Новый ХранилищеЗначения(ТабДок);

Проанализируем ситуацию: в обычных формах ЭлементыФормы.ПолеТабличногоДокумента является визуальным элементом интерфейса (элементом управления), а не чистым объектом типа ТабличныйДокумент. Попытка поместить элемент интерфейса формы напрямую в ХранилищеЗначения приводит к некорректной сериализации. При последующем вызове метода Получить() платформа не может восстановить объект и выдает ошибку формата потока.

Кроме того, при чтении нередко ошибочно пытаются повторно обернуть уже сохраненное хранилище в конструктор Новый ХранилищеЗначения(...), что приводит к получению пустого объекта и ошибкам вывода.

Корректный алгоритм сохранения табличного документа

Рассмотрим правильный порядок действий при сохранении отчета в ХранилищеЗначения:

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

Посмотрим на пример процедуры сохранения отчета в справочник:


Процедура СохранитьОтчетВХранилище()
    
    // Создаем независимый табличный документ
    ТабДок = Новый ТабличныйДокумент;
    ТабДок.Вывести(ЭлементыФормы.ПолеТабличногоДокумента);
    
    // Упаковываем объект в ХранилищеЗначения со сжатием
    Хранилище = Новый ХранилищеЗначения(ТабДок, Новый СжатиеДанных(9));
    
    // Находим или создаем элемент справочника для сохранения
    СправочникСсылка = Справочники.СохраненныеОтчеты.НайтиПоРеквизиту("Период", НачалоМесяца(ДатаОстатков));
    
    Если СправочникСсылка.Пустая() Тогда
        СправочникОбъект = Справочники.СохраненныеОтчеты.СоздатьЭлемент();
        СправочникОбъект.Наименование = "Отчет за " + Формат(ДатаОстатков, "ДФ=MM.yyyy");
        СправочникОбъект.Период = НачалоМесяца(ДатаОстатков);
    Иначе
        СправочникОбъект = СправочникСсылка.ПолучитьОбъект();
    КонецЕсли;
    
    СправочникОбъект.ХранилищеОтчета = Хранилище;
    СправочникОбъект.Записать();
    
КонецПроцедуры

Корректный алгоритм восстановления табличного документа

Разберем процесс чтения данных из хранилища и отображения их пользователю:

  1. Получаем ссылку на нужный элемент справочника.
  2. Обращаемся к реквизиту с типом ХранилищеЗначения и вызываем метод Получить().
  3. Обязательно проверяем полученный результат на Неопределено и соответствие типу ТабличныйДокумент.
  4. Очищаем целевое поле формы и выводим в него восстановленный документ.

Посмотрим на пример процедуры загрузки сохраненного отчета:


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

Практические рекомендации по работе с хранилищем значений

Рассмотрим подробнее важные нюансы, которые необходимо учитывать:

  1. Очистка поля перед выводом: Метод Вывести() последовательно добавляет строки в конец текущего табличного документа. Если не вызывать Очистить() перед загрузкой, при каждом повторном чтении отчет будет дублироваться вниз.
  2. Сжатие данных: Большие отчеты могут занимать десятки мегабайт. Использование параметра Новый СжатиеДанных(9) в конструкторе ХранилищеЗначения позволяет сократить объем занимаемого места в базе данных в несколько раз без потери производительности.
  3. Проверка типа данных: При извлечении через Получить() всегда используйте проверку ТипЗнч(ТабДок) = Тип("ТабличныйДокумент"), чтобы избежать аварийного завершения программы, если в реквизите окажутся устаревшие или несовместимые данные.
  4. Альтернатива для СКД: Если отчет формируется на базе системы компоновки данных, вместо сохранения готового тяжелого табличного документа эффективнее сохранять только настройки отчета (НастройкиКомпоновкиДанных), что занимает доли килобайта и позволяет переформировать отчет в актуальном виде.
← На главную