Разработка и Конфигурация · 10 мин
Как сохранить табличный документ в хранилище значений в 1С
Как сохранить табличный документ в хранилище значений в 1С: код на встроенном языке, чтение обратно, типовые ошибки и ограничения.
Хранилище значений в 1С — универсальный механизм для сохранения произвольных данных прямо в базе: в реквизите объекта, в ресурсе регистра сведений или в константе. Табличный документ (объект ТабличныйДокумент) можно поместить в хранилище целиком, вместе с форматированием, картинками и областями, и потом извлечь его в исходном виде. Это удобно для архива печатных форм, фиксации «снимка» отчёта на дату или передачи документа между сеансами.
Ключевая идея проста: объект ХранилищеЗначения создаётся конструктором Новый ХранилищеЗначения(Значение), куда передаётся сам табличный документ. При этом платформа сериализует объект и упаковывает его во внутренний формат. Обратное чтение выполняется методом Получить(), который возвращает исходный объект.
Ниже разобраны рабочие примеры кода, варианты хранения (реквизит справочника, регистр сведений, временное хранилище), ограничения по объёму и типичные ошибки, из-за которых документ «не читается» обратно.
Как работает хранилище значений с табличным документом
Тип ХранилищеЗначения предназначен для упаковки любых сериализуемых значений — от строк и массивов до сложных объектов вроде табличного документа или картинки. При создании хранилища платформа преобразует объект в поток байт, при чтении — восстанавливает его обратно. Для разработчика это выглядит как «чёрный ящик»: положили документ — получили документ.
Важно понимать, что хранилище значений — не ссылочный тип. Его нельзя «развернуть» запросом или посмотреть содержимое в пользовательском режиме. Единственный способ получить данные — вызвать метод Получить() в коде. Поэтому хранилище подходит для архивов и вложений, но не для данных, по которым нужно строить отборы и отчёты.
Табличный документ сериализуется целиком: значения ячеек, форматирование, объединённые области, вложенные картинки, параметры страницы. После извлечения документ можно показать пользователю, напечатать или сохранить в файл (MXL, Excel, PDF) штатными методами Записать().
Базовый код: сохранить и прочитать документ
Минимальный сценарий — сохранить сформированный табличный документ в реквизит объекта с типом ХранилищеЗначения. Например, в справочнике «ПечатныеФормы» создан реквизит ДанныеДокумента нужного типа.
// Сохранение
ТабДок = Новый ТабличныйДокумент;
// ... заполнение документа ...
НовыйЭлемент = Справочники.ПечатныеФормы.СоздатьЭлемент();
НовыйЭлемент.Наименование = "Счёт № 12 от клиента";
НовыйЭлемент.ДанныеДокумента = Новый ХранилищеЗначения(ТабДок);
НовыйЭлемент.Записать();
// Чтение
Запрос = Новый Запрос("ВЫБРАТЬ ДанныеДокумента ИЗ Справочник.ПечатныеФормы ГДЕ Ссылка = &Ссылка");
Запрос.УстановитьПараметр("Ссылка", НужнаяСсылка);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
ТабДок = Выборка.ДанныеДокумента.Получить();
Если ТипЗнч(ТабДок) = Тип("ТабличныйДокумент") Тогда
ТабДок.Показать("Архивная печатная форма");
КонецЕсли;
КонецЕсли;
Обратите внимание на проверку типа после Получить(). Если реквизит не заполнен, метод вернёт Неопределено, и попытка работать с ним как с табличным документом вызовет ошибку. Проверка типа — обязательная страховка при чтении любых данных из хранилища.
- 1Создайте реквизит объекта или ресурс регистра сведений с типом ХранилищеЗначения
- 2Сформируйте табличный документ программно или получите его из макета
- 3Присвойте реквизиту значение Новый ХранилищеЗначения(ТабДок)
- 4Запишите объект в базу
- 5При чтении вызовите Получить() и проверьте тип результата перед использованием
Где хранить: реквизит объекта, регистр сведений или временное хранилище
Выбор места хранения зависит от задачи. Если табличный документ привязан к конкретному объекту (документу, элементу справочника), логично добавить реквизит с типом ХранилищеЗначения прямо в этот объект. Если нужен архив печатных форм по множеству объектов с версиями — удобнее подчинённый регистр сведений, где измерение — ссылка на объект, а ресурс — хранилище.
Третий сценарий — временное хранилище. Оно не пишет данные в базу, а размещает их в памяти сервера и возвращает адрес (строку навигационной ссылки). Это стандартный способ передать табличный документ с сервера на клиент в управляемых формах, например для показа результата отчёта без сохранения в базу.
// Помещение во временное хранилище (серверная процедура формы)
АдресВХранилище = ПоместитьВоВременноеХранилище(ТабДок, УникальныйИдентификаторФормы);
// Получение обратно
ТабДок = ПолучитьИзВременногоХранилища(АдресВХранилище);
Сравнение вариантов хранения
Подходит, когда документ жёстко привязан к одному объекту. Ограничение: одна версия на объект, при перезаписи старая теряется.
Подходит для архива с версиями и отборами по измерениям. Ограничение: чуть сложнее код записи и чтения.
Подходит для передачи между сервером и клиентом без записи в базу. Ограничение: данные живут только в рамках сеанса или времени жизни формы.
Сжатие и объём хранимых данных
Табличные документы с большим числом строк и оформлением могут занимать заметный объём. Конструктор хранилища поддерживает второй параметр — степень сжатия: Новый ХранилищеЗначения(ТабДок, Новый СжатиеДанных(9)). Сжатие уменьшает размер записи в базе, но немного замедляет запись и чтение. Для архивов, которые пишутся редко, а хранятся долго, сжатие обычно оправдано.
Точного универсального лимита на размер хранилища платформа не фиксирует — практическая граница определяется СУБД и настройками поля. Однако хранение десятков мегабайт в одном реквизите замедляет выборки, репликацию и обмены. Если документы крупные, разумнее сохранять их в файлы (MXL или PDF) в томе хранения файлов, а в базе держать только ссылку на файл.
Типичные ошибки и как их избежать
Чаще всего проблемы возникают не при записи, а при чтении. Первая классическая ошибка — забыть вызвать Получить() и попытаться работать с самим хранилищем как с табличным документом: у объекта ХранилищеЗначения нет методов Показать() или Записать() для MXL. Вторая — отсутствие проверки на Неопределено для пустого реквизита.
Отдельная группа ошибок связана с контекстом выполнения. В тонком клиенте объект ТабличныйДокумент недоступен на клиенте в полном объёме — формировать и упаковывать его нужно в серверной процедуре. Также нельзя записать в хранилище несериализуемые объекты (например, COMОбъект или объект запроса): конструктор выдаст ошибку о невозможности сериализации.
Проверка результата и альтернативы
После записи убедитесь, что данные действительно читаются: выполните чтение в консоли кода или в отладчике, вызовите Получить() и проверьте, что вернулся объект нужного типа и документ открывается с сохранённым оформлением. Полезный контрольный приём — сразу после записи прочитать значение обратно и сравнить, например, количество строк области данных.
Если задача — не архив, а просто передача печатной формы пользователю, хранилище значений может быть избыточным. Альтернативы: запись документа в файл MXL командой ТабДок.Записать(ИмяФайла, ТипФайлаТабличногоДокумента.MXL), использование механизма присоединённых файлов БСП, либо хранение готового PDF для документов, которые больше не будут редактироваться.
Как проверить результат
Возвращается ТабличныйДокумент
Неопределено или другой тип — реквизит пуст или записано не то
Области, форматирование и картинки на месте
Пустой документ — записали незаполненный ТабДок
Рост соответствует числу записей и сжатию
Резкий рост — нет сжатия или пишутся лишние копии
FAQ: частые вопросы
Можно ли сохранить в хранилище значений несколько табличных документов сразу?
Да. Упакуйте их в массив или структуру и передайте эту коллекцию в конструктор хранилища. При чтении Получить() вернёт ту же коллекцию, из которой документы извлекаются по индексу или ключу.
Чем хранилище значений отличается от временного хранилища?
Хранилище значений — объект для записи данных в базу на постоянной основе. Временное хранилище — область памяти сервера с адресом-ссылкой, живущая ограниченное время; оно предназначено для передачи данных между сервером и клиентом, а не для архива.
Почему после Получить() возвращается Неопределено?
Чаще всего реквизит просто не был заполнен при записи объекта, либо запись не выполнилась из-за ошибки или отмены транзакции. Проверьте, что конструктор хранилища вызывался до метода Записать() и что объект успешно записан.
Сохранится ли форматирование и картинки табличного документа?
Да, сериализация охватывает значения ячеек, оформление, объединения, параметры страниц и вложенные картинки. После извлечения документ можно показать или выгрузить в файл без потери внешнего вида.
Можно ли найти нужный документ запросом по содержимому хранилища?
Нет, содержимое хранилища недоступно для отборов и поиска в запросах. Если нужен поиск, храните ключевые реквизиты (номер, дату, контрагента) в отдельных полях объекта рядом с хранилищем.
Что лучше для архива печатных форм — хранилище значений или файлы?
Для небольшого числа документов хранилище проще: всё лежит в базе и копируется вместе с ней. При большом объёме архива выгоднее файловое хранилище или присоединённые файлы — база остаётся компактной, а файлы можно вынести на отдельный диск.
Что важно запомнить
Табличный документ упаковывается конструктором Новый ХранилищеЗначения(ТабДок) и извлекается методом Получить() с обязательной проверкой типа. Место хранения выбирайте по задаче: реквизит объекта, регистр сведений или временное хранилище. Для крупных документов включайте сжатие или переходите на файловое хранение.