Почему не сохраняется значение переменной модуля управляемой формы на сервере и как это исправить

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

При переходе с «обычных» форм (толстого клиента) на «управляемые» (тонкий клиент) разработчики часто сталкиваются с неожиданным поведением системы: переменные, объявленные в модуле формы, внезапно «забывают» свои значения. Давайте подробно разберем, почему это происходит, как устроена работа сервера в 1С 8.3 и какие существуют надежные способы сохранения данных между вызовами.

Анализируем причину: принцип отсутствия состояния (Stateless)

Первым делом выясним причину, по которой переменная мНоменклатура, объявленная через ключевое слово Перем с директивой &НаСервере, оказывается пустой. В управляемом приложении 1С реализована архитектура, в которой серверная часть модуля формы не хранит свое состояние между обращениями клиента. Это критически важно для масштабируемости системы.

Рассмотрим по шагам, что происходит, когда вы открываете форму и вызываете серверные процедуры:

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

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

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

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

Проанализируем этот подход. Если нам нужно хранить список номенклатуры, мы можем создать реквизит формы с типом СписокЗначений или добавить колонку в существующую таблицу данных формы.

Рассмотрим пример реализации:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    // Допустим, у нас есть реквизит формы "СписокНоменклатуры" (тип СписокЗначений)
    Для Каждого ТекНоменклатура Из ПолучитьНужнуюНоменклатуру() Цикл
        СписокНоменклатуры.Добавить(ТекНоменклатура);
    КонецЦикла;
КонецПроцедуры

&НаСервере
Функция ПолучимМассивНоменклатуры()
    // Реквизит формы доступен всегда, его состояние восстанавливается автоматически
    Возврат СписокНоменклатуры.ВыгрузитьЗначения();
КонецФункции

Важный нюанс: Помните о производительности. Все данные реквизитов формы «гоняются» по сети между клиентом и сервером при каждом контекстном вызове (директива &НаСервере). Если ваш массив содержит тысячи элементов, это может замедлить работу интерфейса. В таких случаях стоит рассмотреть второй вариант.

Решение №2: Временное хранилище

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

Разберем алгоритм работы по шагам:

  1. Создаем данные на сервере.
  2. Помещаем их во временное хранилище, привязывая к уникальному идентификатору формы.
  3. Сохраняем адрес этого хранилища в строковом реквизите формы.
  4. При необходимости извлекаем данные по сохраненному адресу.

Посмотрим на пример кода:


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

&НаСервере
Функция ПолучимМассивИзХранилища()
    Если ЭтоАдресВременногоХранилища(АдресХранилища) Тогда
        Возврат ПолучитьИзВременногоХранилища(АдресХранилища);
    Иначе
        Возврат Новый Массив;
    КонецЕсли;
КонецФункции

Этот метод считается наиболее профессиональным, так как он минимизирует трафик между клиентом и сервером: вместо передачи всего массива мы передаем только короткую строку-адрес.

Решение №3: Клиентские переменные

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

Рассмотрим ситуацию: мы один раз получаем массив с сервера и дальше работаем с ним только на клиенте.


&НаКлиенте
Перем мНоменклатураНаКлиенте; // Эта переменная не "умрет"

&НаСервере
Функция СформироватьМассивНаСервере()
    // Здесь логика заполнения
    Результат = Новый Массив;
    Результат.Добавить("Товар 1");
    Возврат Результат;
КонецФункции

&НаКлиенте
Процедура ПриОткрытии(Отказ)
    // Заполняем клиентскую переменную один раз при открытии
    мНоменклатураНаКлиенте = СформироватьМассивНаСервере();
КонецПроцедуры

&НаКлиенте
Процедура КакаяТоДействиеНаКлиенте()
    // Здесь значение мНоменклатураНаКлиенте будет доступно
    Для Каждого Элемент Из мНоменклатураНаКлиенте Цикл
        Сообщить(Элемент);
    КонецЦикла;
КонецПроцедуры

Сравнительный анализ методов

Выясним, какой метод выбрать в зависимости от ситуации:

Подведем итог: Основная ошибка заключалась в ожидании от управляемой формы поведения "толстого" клиента. Запомните: серверный контекст в управляемых формах — это "чистый лист" при каждом новом вызове. Используйте Реквизиты формы или Временное хранилище для долгосрочного хранения данных в процессе работы пользователя с формой.

← На главную