Как правильно передать и сохранить адрес временного хранилища в управляемой форме 1С?

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

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

Анализ проблемы: почему переменная «теряется»?

Проанализируем типичную ошибку, представленную в вопросе. Разработчик объявляет переменную АдресТабSKU непосредственно внутри процедуры ПриОткрытии на клиенте. В языке 1С переменные, объявленные внутри процедур или функций, являются локальными. Это означает, что как только выполнение процедуры завершается, переменная уничтожается, и её значение (в данном случае адрес в памяти сервера) теряется.

Когда управление переходит в другую процедуру, например, УпрАссортиментомПриИзмененииФлажка, система честно сообщает, что знать не знает о существовании АдресТабSKU. Чтобы решить эту проблему, нам нужно обеспечить «выживаемость» переменной на протяжении всего времени работы с формой.

Решение 1: Использование реквизитов формы для хранения адреса

Рассмотрим основной способ сохранения состояния в управляемой форме — создание реквизита формы. В отличие от локальных переменных процедур, реквизиты формы живут столько же, сколько открыто окно формы.

Выполним следующие шаги для настройки формы:

  1. Перейдем в редактор управляемой формы на вкладку «Реквизиты».
  2. Добавим новый реквизит. Назовем его, например, АдресХранилищаSKU.
  3. В качестве типа данных укажем Строка (так как адрес — это всегда строковый идентификатор) или Произвольный. Важный нюанс: использование типа Произвольный удобно тем, что такой реквизит невозможно случайно вытащить на элементы формы, что подчеркивает его служебный характер.

Теперь в коде мы будем обращаться не к локальной переменной, а к реквизиту формы. Рассмотрим обновленный пример кода:


&НаКлиенте
Процедура ПриОткрытии(Отказ)
    // Вызываем серверный метод для подготовки данных
    ПодготовитьДанныеНаСервере();
КонецПроцедуры

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

Решение 2: Управление временем жизни данных (Второй параметр)

Выясним причину, по которой данные могут исчезнуть из хранилища, даже если адрес сохранен правильно. В платформе 1С данные во временном хранилище по умолчанию удаляются сразу после следующего серверного вызова (например, после завершения серверной процедуры, вызванной с клиента).

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

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


&НаКлиенте
Процедура УпрАссортиментомПриИзмененииФлажка(Элемент)
    // Теперь адрес доступен, так как он хранится в реквизите формы
    Если ЗначениеЗаполнено(АдресХранилищаSKU) Тогда
        ОбработатьДанныеНаСервере();
    КонецЕсли;
КонецПроцедуры

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

Важные ограничения: ТаблицаЗначений и Клиент-Сервер

Разберем еще один критический момент, упомянутый в обсуждении. В управляемом приложении (тонкий клиент, веб-клиент) объект типа ТаблицаЗначений не существует на стороне клиента. Попытка создать таблицу значений в процедуре с директивой &НаКлиенте приведет к ошибке компиляции.

Посмотрим, как правильно распределить нагрузку:

  1. Создание данных: Всегда происходит на сервере (директива &НаСервере или &НаСервереБезКонтекста).
  2. Помещение в хранилище: Также выполняется на сервере.
  3. Хранение адреса: Строковый адрес передается на клиент и сохраняется в реквизите формы.
  4. Обработка данных: Когда нужно считать данные, клиент передает адрес обратно на сервер, где происходит вызов ПолучитьИзВременногоХранилища().

Альтернативные подходы к хранению данных

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

Однако временное хранилище остается незаменимым в следующих случаях:

Рекомендации по оптимизации и безопасности

Проанализируем вопросы очистки памяти. Хотя привязка к УникальныйИдентификатор формы автоматически удаляет данные при закрытии окна, в высоконагруженных системах или при работе с очень большими объемами данных (например, массовый импорт из Excel) хорошим тоном считается ручное удаление.

Для этого можно использовать метод:

УдалитьИзВременногоХранилища(АдресХранилищаSKU);

Также, если вам нужно хранить несколько разных объектов (например, таблицу товаров, массив настроек и структуру цен), не обязательно создавать три разных реквизита для адресов. Рассмотрим более элегантный способ: объединим все данные в одну Структуру, поместим её в хранилище и сохраним только один адрес этой структуры.

Посмотрим на пример упаковки данных:


&НаСервере
Процедура СохранитьПакетДанных()
    Контейнер = Новый Структура;
    Контейнер.Вставить("ТаблицаТоваров", ТаблицаТоваров);
    Контейнер.Вставить("Настройки", НастройкиОбхода);
    
    АдресХранилищаSKU = ПоместитьВоВременноеХранилище(Контейнер, УникальныйИдентификатор);
КонецПроцедуры

Таким образом, мы обеспечиваем чистоту кода и эффективное использование ресурсов платформы. Соблюдение этих правил — использование реквизитов формы для хранения адресов, обязательная привязка к идентификатору формы и понимание контекста исполнения (клиент/сервер) — позволит вам избежать большинства ошибок при работе в управляемом интерфейсе 1С.

← На главную