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