Как записать и прочитать ХранилищеЗначения в управляемых формах 1С?

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

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

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

Почему ХранилищеЗначения недоступно в данных формы?

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

Реквизит формы Объект имеет тип ДанныеФормыСтруктура, а не является полноценным объектом базы данных (таким как ДокументОбъект или СправочникОбъект). Платформа намеренно исключает поля типа ХранилищеЗначения из структуры данных формы по следующим причинам:

  1. Оптимизация трафика: В хранилище могут находиться файлы, изображения, огромные массивы или таблицы значений объемом в десятки мегабайт. Если бы эти данные постоянно циркулировали между клиентом и сервером, это привело бы к критическому снижению производительности системы.
  2. Архитектурная чистота: Клиентское приложение не должно напрямую оперировать тяжелыми бинарными данными. Его задача — отображать интерфейс и взаимодействовать с пользователем.

Поэтому для работы с хранилищем значений нам придется использовать специальные «обходные» пути, которые на самом деле являются стандартными паттернами проектирования в 1С.

Способ 1. Запись напрямую через ПередЗаписьюНаСервере

Если нам нужно сформировать таблицу значений (или другую структуру) на сервере непосредственно в момент записи документа, мы можем использовать стандартный обработчик формы ПередЗаписьюНаСервере. В этот обработчик платформа передает параметр ТекущийОбъект, который имеет тип прикладного объекта БД и содержит все его реквизиты, включая недоступное в форме ХранилищеЗначения.

Рассмотрим пример реализации этого подхода:


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

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

Способ 2. Лучшая практика — использование Временного хранилища

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

Давайте разберем этот процесс по шагам:

Шаг 1. Помещение данных во временное хранилище на сервере

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


&НаСервере
Процедура СохранитьТаблицуВоВременноеХранилище()
    
    // Создаем или получаем таблицу значений
    ТЗ = ПолучитьРабочуюТаблицу();
    
    // АдресВХ — это реквизит формы с типом "Строка"
    // УникальныйИдентификатор — стандартный реквизит управляемой формы
    АдресВХ = ПоместитьВоВременноеХранилище(ТЗ, УникальныйИдентификатор);
    
КонецПроцедуры

Шаг 2. Перенос данных из временного хранилища в объект при записи

Теперь в обработчике записи нам достаточно прочитать данные по сохраненному адресу и поместить их в объект базы данных:


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

Как правильно читать данные из ХранилищаЗначения?

Записать данные — это половина дела. Нам также необходимо правильно прочитать сохраненную таблицу при открытии формы документа. Для этого существует два основных сценария. Если выгружаемая таблица имеет динамическую структуру колонок, для ее отображения подойдет пример программного вывода таблицы значений на управляемую форму.

Сценарий А. Чтение при инициализации формы

Для первоначального заполнения формы лучше всего использовать обработчик ПриЧтенииНаСервере. В этот момент объект базы данных уже прочитан из СУБД, и мы имеем к нему полный доступ через параметр ТекущийОбъект.


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

Сценарий Б. Получение данных «на лету» через Навигационную ссылку

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


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

Важные технические нюансы и ограничения

При работе с типом ХранилищеЗначения необходимо помнить о важных правилах, игнорирование которых может привести к трудноотлавливаемым ошибкам в транзакциях:

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

← На главную