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