Как передать Таблицу Значений с клиента на сервер в управляемых формах 1С?

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

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

Давайте разберем эту проблему подробно, выясним причины такого поведения платформы и рассмотрим надежные способы решения задачи.

Почему возникает ошибка передачи мутабельного значения?

В архитектуре управляемого приложения существует четкое разделение контекстов:

  1. Клиент (Тонкий клиент, Веб-клиент) — здесь происходит взаимодействие с пользователем. Этот контекст имеет ограниченный набор типов данных, поэтому инструменты разработчика "Инструментики" для тонкого клиента 1С часто становятся незаменимыми помощниками для отладки и анализа доступных объектов. Для этой задачи есть инструменты разработчика Инструментики для 1С.
  2. Сервер — здесь выполняется основная бизнес-логика и работа с базой данных.

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

Проанализируем три основных способа, как обойти это ограничение и корректно передать данные.

Способ 1: Использование Временного Хранилища

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

Рассмотрим алгоритм действий по шагам.

Шаг 1. Подготовка данных на клиенте

Так как на клиенте нет ТаблицаЗначений, данные у нас обычно хранятся либо в реквизите формы (ДанныеФормыКоллекция), либо мы собираем их в массив структур.

Шаг 2. Помещение во временное хранилище

Для этого используем метод ПоместитьВоВременноеХранилище. Обратите внимание: если мы хотим, чтобы данные очистились автоматически после закрытия формы, нужно передать уникальный идентификатор формы.


&НаКлиенте
Процедура ВыполнитьОбработкуНаСервере()
    
    // АдресВХранилище - строковая переменная
    // ЭтаФорма.УникальныйИдентификатор привязывает данные к жизни формы
    АдресВХранилище = ПоместитьВоВременноеХранилище(Объект.Товары, ЭтаФорма.УникальныйИдентификатор);
    
    // Вызываем серверную процедуру и передаем ТОЛЬКО адрес (строку)
    ОбработатьДанныеНаСервере(АдресВХранилище);
    
КонецПроцедуры

Шаг 3. Получение данных на сервере

На стороне сервера мы используем метод ПолучитьИзВременногоХранилища. В этот момент платформа автоматически преобразует сохраненные данные в ТаблицаЗначений (если исходником были ДанныеФормыКоллекция).


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

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

Способ 2: Массив структур

Если данных немного, и нам не нужна функциональность полноценной таблицы значений (например, индексы, поиск строк, свертка), мы можем использовать Массив, содержащий элементы типа Структура. Оба эти типа данных поддерживаются и на клиенте, и на сервере, и легко сериализуются через XDTO.

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


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

На сервере мы просто принимаем этот параметр.


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

Обратите внимание на использование директивы &НаСервереБезКонтекста. Передача простых коллекций (массивов структур) отлично подходит для внеконтекстных вызовов, что значительно снижает трафик между клиентом и сервером, так как не передается вся форма целиком.

Способ 3: Реквизит формы

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

Однако, если вам нужно создать временную таблицу значений именно для расчетов, которая не должна отображаться пользователю, проанализируем следующий подход:

  1. Добавляем реквизит формы с типом ТаблицаЗначений программно (но это сложно и ресурсоемко, хотя редактор форм в режиме предприятия может облегчить отладку и просмотр свойств созданных элементов). Для этой задачи есть инструмент для пошаговой отладки кода 1С.
  2. Лучше использовать Временное Хранилище, как описано в первом способе.

Как вернуть обработанную Таблицу Значений обратно на клиент?

Часто возникает обратная задача: мы сформировали отчет или таблицу на сервере и хотим показать ее пользователю. Посмотрим, как это сделать.

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

Рассмотрим пример загрузки серверной ТЗ в табличную часть формы для отображения пользователю:


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

Здесь создание кода новой таблицы значений из реквизита на форме может сэкономить время при написании инициализации ТЗ. Метод ЗначениеВДанныеФормы является ключевым для конвертации серверного объекта ТаблицаЗначений в визуальный компонент управляемой формы.

Резюме и рекомендации

Подводя итог нашему анализу проблемы передачи данных, выделим основные правила:

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

← На главную