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

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

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

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

Причина проблемы: почему ПриЗаписиНаСервере не подходит

Главная причина, по которой значение не записывается при вызове процедуры ПриЗаписиНаСервере, заключается в порядке выполнения событий платформы 1С при сохранении объекта.

Рассмотрим последовательность действий платформы при записи элемента из управляемой формы:

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

Таким образом, модифицировать реквизиты объекта (включая реквизиты типа ХранилищеЗначения) в процедуре ПриЗаписиНаСервере слишком поздно.

Решение 1. Использование обработчиков ПередЗаписьюНаСервере и ПриЧтенииНаСервере

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

  1. Запись значения в ТекущийОбъект выполняется строго в процедуре ПередЗаписьюНаСервере.
  2. Извлечение значения из базы данных в реквизиты формы происходит при считывании объекта в процедуре ПриЧтенииНаСервере.

Рассмотрим пример кода на сервере:


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

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

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

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

  1. Реквизиты типа ХранилищеЗначения не передаются на клиент. В структуре данных формы (Объект типа ДанныеФормыСтруктура) реквизиты с этим типом не содержат бинарных данных. Обращаться к ним напрямую на клиенте нельзя. Работа с ними должна вестись через реквизиты формы соответствующих типов (например, реквизит формы Шрифт с типом Шрифт).
  2. Системные шрифты и цвета не всегда сериализуются. Если значение типа Шрифт или Цвет получено из системных настроек или темы оформления, при попытке помещения его в ХранилищеЗначения платформа может записать неполный объект. Чтобы избежать этого, создавайте абсолютные объекты, например: Новый Шрифт("Arial", 10, Истина) или Новый Цвет(255, 0, 0).
  3. Использование временного хранилища. Для передачи больших объемов данных или файлов между клиентом и сервером рекомендуется сначала использовать ПоместитьВоВременноеХранилище(), а уже в процедуре ПередЗаписьюНаСервере извлекать эти данные через ПолучитьИзВременногоХранилища() и записывать в реквизит объекта.

Альтернативный вариант: сохранение параметров в примитивных типах

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

  1. Создание примитивных реквизитов: реквизиты справочника ИмяШрифта (Строка), РазмерШрифта (Число), ШрифтBold (Булево). Это упрощает отбор и просмотр данных в СУБД, так как данные из ХранилищаЗначения недоступны в запросах.
  2. Сериализация через XDTO: сохранение сложного объекта в реквизит типа Строка неограниченной длины с помощью вызовов СериализаторXDTO.ЗаписатьXML() и СериализаторXDTO.ПрочитатьXML().
← На главную