Как правильно работать с таблицей значений на сервере, если она является реквизитом формы?

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

Часто начинающие разработчики сталкиваются с ситуацией: в одной серверной процедуре управляемой формы мы заполняем реквизит типа ТаблицаЗначений, а при попытке обратиться к нему в другой серверной процедуре этой же формы, он оказывается пустым. Обычно это связано с неправильным пониманием механики работы с данными формы на сервере и избыточным использованием функций преобразования. Давайте разберемся, как правильно организовать работу с табличными данными на форме, чтобы избежать подобных ошибок.

Проанализируем типичную проблему: разработчик заполняет таблицу значений, преобразует ее с помощью ЗначениеВРеквизитФормы(), а в другом серверном вызове пытается получить ее обратно через РеквизитФормыВЗначение() и обнаруживает, что таблица пуста. Выясним, почему так происходит и как действовать правильно.

Причина ошибки: избыточные преобразования и непонимание контекста

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

Функции РеквизитФормыВЗначение() и ЗначениеВРеквизитФормы() создают новые копии данных. Когда вы выполняете таб = РеквизитФормыВЗначение("ТабРеквизит"), вы создаете новую, независимую переменную таб, которая является копией данных реквизита. Любые изменения в этой переменной не отразятся на реквизите формы, и наоборот. В этом и кроется корень проблемы.

Платформа 1С "сшивает" контекст между серверными вызовами в рамках одной открытой формы. Это означает, что данные, которые вы записали в реквизит формы в одной процедуре, будут доступны в другой процедуре той же формы без каких-либо дополнительных действий.

Решение 1: Прямая работа с реквизитом формы (основной способ)

Самый простой и правильный способ — обращаться к реквизиту напрямую по его имени. Рассмотрим по шагам, как это должно выглядеть.

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

  1. Заполнение таблицы на сервере.

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

    
    &НаСервере
    Процедура ЗаполнитьТаблицуНаСервере()
        // Создаем таблицу-источник. На практике это может быть результат запроса.
        ТЗ_Источник = Новый ТаблицаЗначений;
        ТЗ_Источник.Колонки.Добавить("Номенклатура");
        ТЗ_Источник.Колонки.Добавить("Количество");
        
        НоваяСтрока = ТЗ_Источник.Добавить();
        НоваяСтрока.Номенклатура = "Товар 1";
        НоваяСтрока.Количество = 10;
        
        // Просто присваиваем данные реквизиту формы.
        // Не нужно использовать ЗначениеВРеквизитФормы()!
        ТабРеквизит = ТЗ_Источник;
    КонецПроцедуры
    
  2. Использование данных в другой процедуре.

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

    
    &НаСервере
    Процедура НайтиДанныеВТаблицеНаСервере()
        // Обращаемся к реквизиту напрямую, без РеквизитФормыВЗначение()
        
        // Проверяем, что таблица не пустая
        Если ТабРеквизит.Количество() > 0 Тогда
            // Ищем строки по условию
            ПараметрыПоиска = Новый Структура("Номенклатура", "Товар 1");
            НайденныеСтроки = ТабРеквизит.НайтиСтроки(ПараметрыПоиска);
            
            Если НайденныеСтроки.Количество() > 0 Тогда
                Сообщить("Найдено " + НайденныеСтроки.Количество() + " строк. Количество в первой найденной: " + НайденныеСтроки[0].Количество);
            Иначе
                Сообщить("Строки не найдены.");
            КонецЕсли;
        Иначе
            Сообщить("Таблица в реквизите формы пуста!");
        КонецЕсли;
    КонецПроцедуры
    

Важное замечание: В старых примерах можно встретить обращение через ЭтаФорма.ТабРеквизит или ЭтотОбъект.ТабРеквизит. В современных версиях платформы 1С это избыточно. В серверном коде модуля формы можно обращаться к ее реквизитам просто по имени.

Решение 2: Оптимизация для больших объемов данных (Временное хранилище)

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

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

Механизм работы следующий:

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

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

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

Добавим на форму реквизит АдресТаблицыВХранилище с типом Строка.


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

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

Резюме

Давайте подведем итог, когда какой способ использовать:

  1. Прямая работа с реквизитом формы: Используйте этот метод, если таблица содержит данные для отображения пользователю или ее объем невелик (сотни, максимум несколько тысяч строк). Это основной и самый простой способ.
  2. Временное хранилище: Используйте этот метод для обработки больших объемов данных на сервере, которые не нужно показывать пользователю. Это позволяет избежать передачи "тяжелых" данных между клиентом и сервером и значительно повышает производительность.

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

← На главную