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