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