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