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