Как сохранить и восстановить табличный документ в ХранилищеЗначения без ошибок

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

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

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

Почему возникает «Ошибка формата потока»?

Проанализируем типичную ситуацию. Программист пытается сохранить элемент формы напрямую:

Результат = Новый ХранилищеЗначения(ЭлементыФормы.ТПОценочныйЛист);

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

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

Правильное сохранение табличного документа

Рассмотрим, как правильно получить объект данных из элемента формы. В обычных формах (как в примере автора темы) у элемента управления есть свойство Значение или связанная с ним переменная. Если само поле является источником данных типа ТабличныйДокумент, нам нужно обращаться именно к нему.

Разберем по шагам правильный алгоритм сохранения:

  1. Создаем объект типа ТабличныйДокумент.
  2. Копируем в него содержимое из экранного поля.
  3. Помещаем этот объект в ХранилищеЗначения.

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


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

Объект.РезультатХранилище = Новый ХранилищеЗначения(ТабДокДляСохранения, Новый СжатиеДанных(9));

Восстановление данных при открытии формы

Теперь выясним, как правильно вывести сохраненный документ обратно на форму. Вместо того чтобы пытаться присвоить полученный объект всему элементу формы, мы должны использовать метод Вывести() или загрузить данные в существующий объект на форме.

Рассмотрим пример восстановления:


Если ЗначениеЗаполнено(Объект.РезультатХранилище) Тогда
    ДанныеИзХранилища = Объект.РезультатХранилище.Получить();
    
    Если ТипЗнч(ДанныеИзХранилища) = Тип("ТабличныйДокумент") Тогда
        // Очищаем текущее поле перед выводом
        ЭлементыФормы.ТПОценочныйЛист.Очистить();
        // Выводим сохраненный документ в поле
        ЭлементыФормы.ТПОценочныйЛист.Вывести(ДанныеИзХранилища);
    КонецЕсли;
КонецЕсли;

Важное примечание: Метод Вывести() добавляет данные к уже имеющимся. Если вам нужно полное восстановление «один в один», убедитесь, что вы предварительно вызвали метод Очистить().

Особенности для управляемых форм (v8.3)

Если вы работаете в современном интерфейсе «Такси» на управляемых формах, ситуация упрощается, но требует понимания клиент-серверного взаимодействия. Реквизит формы с типом ТабличныйДокумент на сервере уже является объектом данных. Его не нужно извлекать из элементов интерфейса.

Проанализируем пример для управляемого приложения:


&НаСервере
Процедура СохранитьТабДокВХранилище()
    // РеквизитФормы.ТабДок - это реквизит с типом ТабличныйДокумент
    Объект.ДанныеДокумента = Новый ХранилищеЗначения(РеквизитФормы.ТабДок);
КонецПроцедуры

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

Оптимизация хранения

Табличные документы могут быть очень объемными, особенно если в них много раскрашенных ячеек или внедренных картинок. Чтобы база данных не росла слишком быстро, рекомендуем использовать следующие приемы:

Альтернативные методы: XML и MXL

В некоторых случаях использование ХранилищеЗначения может быть неудобным (например, если нужно передать этот документ во внешнюю систему или другую базу 1С). Тогда рассмотрим альтернативные варианты:

  1. Формат MXL: Вы можете сохранить табличный документ во временный файл методом Записать(ИмяФайла, ТипФайлаТабличногоДокумента.MXL) и передать его как файл.
  2. Сериализация в XML: 1С поддерживает нативную сериализацию табличных документов в XML-строку. Это позволяет хранить документ в обычном текстовом реквизите неограниченной длины.

Подведем итог: залог успеха при работе с хранилищем — четкое разделение данных и их визуального представления. Сохраняйте объект ТабличныйДокумент, используйте сжатие и всегда проверяйте данные при чтении. Это обеспечит стабильную работу вашего прикладного решения.

← На главную