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