Как передать Таблицу Значений с клиента на сервер в 1С:Предприятие 8.3?

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

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

Суть проблемы и архитектурные ограничения

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

Разберем причину. Согласно архитектуре платформы 1С:

  1. Объект ТаблицаЗначений доступен только на сервере и в толстом клиенте.
  2. На тонком клиенте (и веб-клиенте) такого типа данных не существует.
  3. Механизм сериализации XDTO, отвечающий за передачу данных между клиентом и сервером, не умеет напрямую преобразовывать произвольную таблицу значений.

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

Способ 1: Использование Временного хранилища (Рекомендуемый)

Этот метод является наиболее универсальным и подходит для передачи больших объемов данных. Идея заключается в том, чтобы поместить данные во временное хранилище на клиенте (или сервере в контексте формы), получить адрес, передать строку адреса на сервер, и там извлечь данные.

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

Если данные собираются на клиенте, алгоритм действий будет следующим:

  1. Собираем данные в массив структур (так как структуры доступны на клиенте).
  2. Передаем этот массив во временное хранилище.
  3. На сервере получаем массив и загружаем его в Таблицу Значений.

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


// На Сервере (или в серверной процедуре формы)
АдресВХранилище = ПоместитьВоВременноеХранилище(НашаТаблицаЗначений, УникальныйИдентификатор);

// Возвращаем АдресВХранилище на Клиент
// ... выполняем какие-то действия на Клиенте ...

// Снова вызываем Сервер и передаем Адрес
МояСервернаяПроцедура(АдресВХранилище);

Внутри целевой серверной процедуры мы восстанавливаем таблицу:


Процедура МояСервернаяПроцедура(АдресВХранилище)
    
    // Получаем данные из хранилища
    ПолученнаяТаблица = ПолучитьИзВременногоХранилища(АдресВХранилище);
    
    Если ТипЗнч(ПолученнаяТаблица) = Тип("ТаблицаЗначений") Тогда
        // Работаем с таблицей
    КонецЕсли;
    
КонецПроцедуры

Важно: При использовании метода ПоместитьВоВременноеХранилище вторым параметром рекомендуется указывать Уникальный Идентификатор формы (УникальныйИдентификатор). Это гарантирует, что данные будут очищены автоматически при закрытии формы.

Способ 2: Использование Массива Структур

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

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


// Функция преобразования Таблицы значений в Массив структур
// Выполняется НА СЕРВЕРЕ перед возвратом данных на клиент
Функция ТЗвМассив(ТаблицаЗначений)
    
    МассивРезультат = Новый Массив;
    
    Для Каждого СтрокаТЗ Из ТаблицаЗначений Цикл
        СтруктураСтроки = Новый Структура;
        // Заполняем структуру данными колонок
        Для Каждого Колонка Из ТаблицаЗначений.Колонки Цикл
            СтруктураСтроки.Вставить(Колонка.Имя, СтрокаТЗ[Колонка.Имя]);
        КонецЦикла;
        МассивРезультат.Добавить(СтруктураСтроки);
    КонецЦикла;
    
    Возврат МассивРезультат;
    
КонецФункции

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

На принимающей стороне (на сервере) нам может потребоваться обратное преобразование в ТаблицаЗначений. Рассмотрим код для восстановления:


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

Способ 3: Реквизиты формы (ДанныеФормыКоллекция)

Если таблица, которую вы хотите передать, отображается на форме пользователю, то она уже существует в виде реквизита формы. В этом случае тип данных этой таблицы — ДанныеФормыКоллекция.

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

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


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

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

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

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

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

← На главную