Почему не работает ЗначениеВРеквизитФормы для ХранилищаЗначения в ПриСозданииНаСервере и как это исправить?

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

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

В чем заключается корень проблемы?

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

  1. Преобразование реквизита формы в прикладной объект через РеквизитФормыВЗначение("Объект").
  2. Присвоение значения в поле типа ХранилищеЗначения.
  3. Обратное преобразование через ЗначениеВРеквизитФормы(ОбъектОбъект, "Объект").

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

Разберем механизм работы ЗначениеВРеквизитФормы

Когда мы вызываем ЗначениеВРеквизитФормы, платформа пытается спроецировать свойства прикладного объекта (например, СправочникОбъект) на структуру данных формы. Если в объекте есть поле типа ХранилищеЗначения, то в соответствующем поле реквизита формы данных просто не окажется, так как в структуре формы для него не предусмотрено места. Таким образом, даже если вы успешно записали данные в объект в памяти сервера, после выполнения синхронизации с формой эти данные «исчезают» для формы, а при последующей записи объекта из формы в базу данных — затираются пустым значением.

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

Методически верным решением в 1С является использование механизма Временного хранилища. Рассмотрим, как реализовать передачу и сохранение данных по шагам.

Шаг 1. Помещение данных во временное хранилище перед открытием формы.

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


ПараметрыФормы = Новый Структура;
Адрес = ПоместитьВоВременноеХранилище(ВашиБинарныеДанные, ЭтаФорма.УникальныйИдентификатор);
ПараметрыФормы.Вставить("АдресДанных", Адрес);

ОткрытьФорму("Справочник.ВашСправочник.ФормаОбъекта", ПараметрыФормы);

Шаг 2. Сохранение адреса в реквизите формы.

В самой форме создадим строковый реквизит (не входящий в состав объекта), например, АдресБинарныхДанных. В обработчике ПриСозданииНаСервере мы просто запомним этот адрес.


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    Если Параметры.Свойство("АдресДанных") Тогда
        ЭтаФорма.АдресБинарныхДанных = Параметры.АдресДанных;
    КонецЕсли;
КонецПроцедуры

Шаг 3. Запись данных в объект непосредственно перед сохранением в базу.

Чтобы данные попали в базу данных, их нужно поместить в объект именно в тот момент, когда происходит запись. Оптимальное место для этого — обработчик ПередЗаписьюНаСервере.


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

Почему это работает?

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

Особенности работы с существующими объектами (ПриЧтенииНаСервере)

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

Проанализируем пример кода для извлечения данных:


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

Таким образом, мы обеспечиваем сквозную работу с «тяжелыми» данными, не перегружая форму и избегая ошибок синхронизации ЗначениеВРеквизитФормы.

Важные нюансы при работе с ХранилищемЗначения

Подводя итог, можно сказать, что ЗначениеВРеквизитФормы в ПриСозданииНаСервере работает абсолютно штатно. Оно просто не предназначено для пробрасывания типов, которые не могут существовать на стороне клиента. Используйте Временное хранилище и события ПередЗаписьюНаСервере или ПриЧтенииНаСервере — это стандарт индустрии разработки на 1С.

← На главную