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