При разработке на платформе 1С:Предприятие 8.3 в режиме управляемых форм программисты часто сталкиваются с ситуацией, когда попытка программно заполнить реквизиты объекта данными в обработчике ПриСозданииНаСервере не приводит к желаемому результату. Особенно остро эта проблема стоит при работе с типом ХранилищеЗначения. Рассмотрим подробнее, почему стандартный механизм синхронизации данных кажется «нерабочим», и разберем правильную методику решения этой задачи.
Проанализируем ситуацию: разработчик пытается передать бинарные данные (картинку, файл или структуру) через параметры формы в виде объекта ХранилищеЗначения. Внутри обработчика ПриСозданииНаСервере выполняется стандартная последовательность действий:
РеквизитФормыВЗначение("Объект").ХранилищеЗначения.ЗначениеВРеквизитФормы(ОбъектОбъект, "Объект").После выполнения этих действий программист обнаруживает, что данные в реквизите Объект.ИмяХранилища пусты или равны Неопределено. Выясним причину этого поведения. Все дело в архитектуре управляемого приложения. Реквизиты формы (тип ДанныеФормыСтруктура) — это специализированные объекты, предназначенные для отображения данных на клиенте и минимизации трафика между клиентом и сервером. Тип ХранилищеЗначения не поддерживается данными формы. Платформа намеренно игнорирует или очищает этот тип при передаче на клиент, так как бинарные данные могут быть огромными, и их автоматическая пересылка «убьет» производительность интерфейса.
Когда мы вызываем ЗначениеВРеквизитФормы, платформа пытается спроецировать свойства прикладного объекта (например, СправочникОбъект) на структуру данных формы. Если в объекте есть поле типа ХранилищеЗначения, то в соответствующем поле реквизита формы данных просто не окажется, так как в структуре формы для него не предусмотрено места. Таким образом, даже если вы успешно записали данные в объект в памяти сервера, после выполнения синхронизации с формой эти данные «исчезают» для формы, а при последующей записи объекта из формы в базу данных — затираются пустым значением.
Методически верным решением в 1С является использование механизма Временного хранилища. Рассмотрим, как реализовать передачу и сохранение данных по шагам.
Шаг 1. Помещение данных во временное хранилище перед открытием формы.
В коде, который открывает форму (например, в команде или другой форме), необходимо поместить данные во временное хранилище и передать полученный адрес в параметры открытия.
ПараметрыФормы = Новый Структура;
Адрес = ПоместитьВоВременноеХранилище(ВашиБинарныеДанные, ЭтаФорма.УникальныйИдентификатор);
ПараметрыФормы.Вставить("АдресДанных", Адрес);
ОткрытьФорму("Справочник.ВашСправочник.ФормаОбъекта", ПараметрыФормы);
Шаг 2. Сохранение адреса в реквизите формы.
В самой форме создадим строковый реквизит (не входящий в состав объекта), например, АдресБинарныхДанных. В обработчике ПриСозданииНаСервере мы просто запомним этот адрес.
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Если Параметры.Свойство("АдресДанных") Тогда
ЭтаФорма.АдресБинарныхДанных = Параметры.АдресДанных;
КонецЕсли;
КонецПроцедуры
Шаг 3. Запись данных в объект непосредственно перед сохранением в базу.
Чтобы данные попали в базу данных, их нужно поместить в объект именно в тот момент, когда происходит запись. Оптимальное место для этого — обработчик ПередЗаписьюНаСервере.
&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
// Проверяем, есть ли у нас адрес с новыми данными
Если ЗначениеЗаполнено(ЭтаФорма.АдресБинарныхДанных) Тогда
// Получаем данные из хранилища по адресу
ДанныеДляЗаписи = ПолучитьИзВременногоХранилища(ЭтаФорма.АдресБинарныхДанных);
// Помещаем их в реквизит объекта
ТекущийОбъект.ДанныеХранилища = Новый ХранилищеЗначения(ДанныеДляЗаписи);
// Очищаем адрес, чтобы не записывать одно и то же повторно, если это нужно
ЭтаФорма.АдресБинарныхДанных = "";
КонецЕсли;
КонецПроцедуры
В обработчике ПередЗаписьюНаСервере в параметре ТекущийОбъект нам доступен реальный прикладной объект (СправочникОбъект, ДокументОбъект), который еще не записан в БД, но уже наполнен данными из формы. Поскольку этот объект существует только на сервере в рамках текущего вызова, мы можем спокойно присвоить его реквизиту значение типа ХранилищеЗначения. Платформа увидит изменения в объекте и корректно запишет их в SQL-таблицу.
Посмотрим на ситуацию, когда нам нужно не записать, а прочитать ХранилищеЗначения в форме. Как мы уже выяснили, в реквизите Объект его не будет. Для этого используется обработчик ПриЧтенииНаСервере.
Проанализируем пример кода для извлечения данных:
&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)
// Извлекаем данные из хранилища объекта базы данных
БинарныеДанные = ТекущийОбъект.ДанныеХранилища.Получить();
// Если данные есть, помещаем их во временное хранилище, чтобы с ними мог работать клиент
Если БинарныеДанные <> Неопределено Тогда
ЭтаФорма.АдресБинарныхДанных = ПоместитьВоВременноеХранилище(БинарныеДанные, ЭтаФорма.УникальныйИдентификатор);
КонецЕсли;
КонецПроцедуры
Таким образом, мы обеспечиваем сквозную работу с «тяжелыми» данными, не перегружая форму и избегая ошибок синхронизации ЗначениеВРеквизитФормы.
ХранилищаЗначения, обязательно убедитесь, что платформа поняла, что объект изменен. При явном присвоении Новый ХранилищеЗначения(...) это происходит автоматически.УникальныйИдентификатор формы при помещении данных во временное хранилище. Это гарантирует, что данные будут удалены из оперативной памяти сервера сразу после закрытия формы.ТекущийОбъект в системных событиях записи.Подводя итог, можно сказать, что ЗначениеВРеквизитФормы в ПриСозданииНаСервере работает абсолютно штатно. Оно просто не предназначено для пробрасывания типов, которые не могут существовать на стороне клиента. Используйте Временное хранилище и события ПередЗаписьюНаСервере или ПриЧтенииНаСервере — это стандарт индустрии разработки на 1С.