Почему ПолучитьИзВременногоХранилища возвращает Неопределено вместо таблицы значений?

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

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

Разберем детально механизм работы временного хранилища, выясним причину такого поведения и рассмотрим правильные варианты реализации.

Причина проблемы: время жизни данных во временном хранилище

Проанализируем механику работы функции ПоместитьВоВременноеХранилище. У данной функции есть два параметра:

  1. Значение — объект, который необходимо поместить в хранилище (например, ТаблицаЗначений или Структура).
  2. УникальныйИдентификатор — адрес или уникальный идентификатор формы/сеанса, определяющий время жизни помещенных данных.

Если второй параметр не указан, данные во временном хранилище живут только до следующего клиент-серверного вызова в рамках текущего сеанса. Посмотрим, что происходит в исходном коде при последовательных серверных вызовах с клиента:


&НаКлиенте
Процедура Подбор(Команда)
    ...
    // Первый серверный вызов: помещаем первую таблицу без привязки к форме
    АдресТаблицыП = ПоместитьТаблицуПВХранилищеНаСервере();
    
    // Второй серверный вызов: проверяем таблицу или выполняем другие действия
    ПроверитьТаблицу(АдресТаблицыП);
    
    // Третий серверный вызов: помещаем вторую таблицу без привязки к форме
    АдресХарактеристик = ПоместитьТаблицуХарактеристикВХранилищеНаСервере();
    
    // Четвертый вызов: открытие формы, где на сервере происходит попытка прочитать адреса
    ОткрытьФорму(...);
КонецПроцедуры

Каждый новый серверный вызов без указания идентификатора формы очищает данные, помещенные в хранилище во время предыдущих безадресных вызовов. В результате к моменту создания подчиненной формы адрес первой таблицы уже указывает на очищенную область памяти, и функция ПолучитьИзВременногоХранилища возвращает значение Неопределено.

Решение 1. Привязка времени жизни данных к форме-владельцу

Чтобы данные не удалялись между серверными вызовами, необходимо привязать их ко времени жизни текущей формы. Для этого во второй параметр функции ПоместитьВоВременноеХранилище передается уникальный идентификатор формы (УникальныйИдентификатор):


&НаСервере
Функция ПоместитьТаблицуПВХранилищеНаСервере()
    Таблица = РеквизитФормыВЗначение("П", Тип("ТаблицаЗначений"));
    // Передаем УникальныйИдентификатор формы вторым параметром
    Возврат ПоместитьВоВременноеХранилище(Таблица, УникальныйИдентификатор);
КонецФункции

&НаСервере
Функция ПоместитьТаблицуХарактеристикВХранилищеНаСервере()
    Таблица = РеквизитФормыВЗначение("Х", Тип("ТаблицаЗначений"));
    // Передаем УникальныйИдентификатор формы вторым параметром
    Возврат ПоместитьВоВременноеХранилище(Таблица, УникальныйИдентификатор);
КонецФункции

При таком подходе данные будут храниться на сервере до тех пор, пока форма-владелец открыта. Когда пользователь закроет форму, платформа 1С автоматически освободит занятую память.

Решение 2. Оптимизация и объединение данных в одну структуру

Выполнять несколько последовательных серверных вызовов подряд ради помещения каждой отдельной таблицы — неоптимальная практика, создающая лишнюю сетевую нагрузку. Гораздо эффективнее объединить подготовку данных в один серверный метод и поместить в хранилище общую структуру:


&НаСервере
Функция ПодготовитьДанныеДляПодбораНаСервере()
    СтруктураДанных = Новый Структура;
    СтруктураДанных.Вставить("ТаблицаП", РеквизитФормыВЗначение("П", Тип("ТаблицаЗначений")));
    СтруктураДанных.Вставить("ТаблицаХарактеристик", РеквизитФормыВЗначение("Х", Тип("ТаблицаЗначений")));
    
    Возврат ПоместитьВоВременноеХранилище(СтруктураДанных, УникальныйИдентификатор);
КонецФункции

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

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


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

Альтернативный вариант: привязка к сеансу пользователя

Если требуется передать данные в фоновое задание или между формами, которые не связаны отношением владелец-подчиненный, можно привязать данные ко всему сеансу. Для этого создается новый уникальный идентификатор:


АдресВХ = ПоместитьВоВременноеХранилище(ТаблицаЗначений, Новый УникальныйИдентификатор());

Важно: данные с таким идентификатором будут храниться в оперативной памяти сервера до завершения сеанса пользователя. Чтобы избежать утечек памяти, после считывания данных в принимающей форме следует явно очищать хранилище с помощью метода УдалитьИзВременногоХранилища(АдресВХ).

← На главную