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