К статье
Практический материал

Разработка и Конфигурация · 12 мин

Как передать таблицу значений с сервера на клиент в 1С 8.3

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

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

Основных подхода три: преобразование таблицы в реквизит формы типа «ТаблицаЗначений» или «ДинамическийСписок», сериализация таблицы через «ЗначениеВСтрокуВнутр» или помещение во временное хранилище, а также универсальный способ — преобразование таблицы в массив структур, который свободно передаётся между контекстами. Выбор зависит от того, нужна ли таблица на форме, насколько она велика и требуется ли обратная передача на сервер.

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

Почему таблицу значений нельзя передать напрямую

Платформа 1С:Предприятие 8.3 в клиент-серверной архитектуре разделяет исполняемый код на клиентский и серверный контексты. Между ними данные передаются сериализацией, и набор допустимых типов строго ограничен: примитивные типы (число, строка, дата, булево), ссылки на объекты базы, структуры, массивы, соответствия и некоторые универсальные коллекции.

Тип «ТаблицаЗначений» в этот список не входит, если речь идёт о возврате значения из серверной процедуры в клиентскую вне контекста формы. Это связано с тем, что таблица значений — тяжёлый объект со своей внутренней структурой колонок, индексов и типизации, который платформа не умеет автоматически упаковывать для передачи по соединению.

Исключение — реквизиты формы. Если таблица объявлена как реквизит управляемой формы, платформа сама обеспечивает её синхронизацию между сервером и клиентом при вызовах серверных процедур формы. Именно поэтому самый «платформенный» способ — работать через реквизит формы, а не через возвращаемые значения.

Способ 1. Реквизит формы типа «ТаблицаЗначений»

Самый надёжный и рекомендуемый способ, когда таблица нужна на форме для отображения или дальнейшей работы пользователя. Создайте в конфигураторе реквизит формы с типом «ТаблицаЗначений», добавьте в него колонки нужных типов и выведите реквизит на форму как табличное поле.

В серверной процедуре формы заполните обычную таблицу значений (например, результатом запроса) и загрузите её в реквизит формы методом ЗначениеВРеквизитФормы(). Платформа сама передаст данные на клиент при возврате управления из серверного вызова.

&НаСервере

Процедура ЗаполнитьТаблицуНаСервере()

Запрос = Новый Запрос(

"ВЫБРАТЬ ПЕРВЫЕ 100

| Номенклатура.Ссылка КАК Товар,

| Номенклатура.Код КАК Код

|ИЗ Справочник.Номенклатура КАК Номенклатура");

ТЗ = Запрос.Выполнить().Выгрузить();

ЗначениеВРеквизитФормы(ТЗ, "ТаблицаТоваров");

КонецПроцедуры

&НаКлиенте

Процедура Заполнить(Команда)

ЗаполнитьТаблицуНаСервере();

// данные уже доступны в реквизите ТаблицаТоваров

КонецПроцедуры

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

Если структура колонок заранее неизвестна и формируется динамически, используйте программное создание реквизитов формы через метод ИзменитьРеквизиты() с массивом объектов «РеквизитФормы». Это сложнее, но позволяет строить таблицы произвольной структуры в универсальных обработках.

Способ 2. Временное хранилище

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

&НаСервере

Функция ПолучитьАдресТаблицы()

ТЗ = Новый ТаблицаЗначений;

ТЗ.Колонки.Добавить("Номенклатура");

ТЗ.Колонки.Добавить("Количество");

// ... заполнение таблицы

Возврат ПоместитьВоВременноеХранилище(ТЗ,

УникальныйИдентификаторФормы);

КонецФункции

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

Второй параметр — уникальный идентификатор формы — важен. Он привязывает данные к времени жизни формы: пока форма открыта, данные в хранилище гарантированно доступны. Если передать Неопределено, данные будут удалены после завершения серверного вызова, и клиент получит адрес пустого хранилища.

Способ 3. Массив структур вместо таблицы

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

&НаСервере

Функция ТаблицаВМассивСтруктур(ТЗ)

Результат = Новый Массив;

ИменаКолонок = "";

Для Каждого Колонка Из ТЗ.Колонки Цикл

ИменаКолонок = ИменаКолонок + ?(ИменаКолонок = "", "", ",")

+ Колонка.Имя;

КонецЦикла;

Для Каждого СтрокаТЗ Из ТЗ Цикл

СтруктураСтроки = Новый Структура(ИменаКолонок);

ЗаполнитьЗначенияСвойств(СтруктураСтроки, СтрокаТЗ);

Результат.Добавить(СтруктураСтроки);

КонецЦикла;

Возврат Результат;

КонецФункции

На клиенте данные доступны как обычный массив: можно перебрать его циклом, обратиться к полям через точку, передать дальше в другие процедуры. Для обратной передачи массив структур отправляется на сервер, где по нему заново строится таблица значений — добавляются колонки и строки в цикле.

У способа есть ограничения. Значения внутри структур тоже должны быть сериализуемыми: примитивы, ссылки, даты. Вложенная таблица значений или картинка так не передадутся. Кроме того, теряется типизация колонок и индексы — если на клиенте нужен поиск по таблице, придётся перебирать массив вручную.

Для таблиц до нескольких тысяч строк массив структур работает быстрее и проще, чем реквизит формы, особенно если данные нужны только для чтения на клиенте. Для больших объёмов и редактируемых данных реквизит формы удобнее — платформа сама следит за синхронизацией.
ПЗ
Практическое замечание

Сравнение способов и критерии выбора

Единого «правильного» способа нет — выбор зависит от сценария. Ниже сведены ключевые различия трёх подходов.

КритерийРеквизит формыВременное хранилищеМассив структур
Отображение на формеДа, напрямуюТребуется загрузка в реквизитТребуется загрузка в реквизит
Работа вне формыНетДаДа
Передача в другую формуЧерез хранилищеДа, по адресуЧерез параметры
Обратная передача на серверАвтоматическиПо адресуПараметром вызова
Динамические колонкиЧерез ИзменитьРеквизитыБез ограниченийБез ограничений
Нагрузка на трафикСредняяНизкая (данные на сервере)Высокая при больших объёмах
Маршрут решения

Как выбрать способ

Таблица отображается и редактируется на текущей формеИспользуйте реквизит формы типа «ТаблицаЗначений» и ЗначениеВРеквизитФормы
Таблицу нужно передать в другую форму или обработкуПоместите таблицу во временное хранилище и передайте адрес
Данные нужны на клиенте только для чтения или расчётовПреобразуйте таблицу в массив структур
Объём данных велик (десятки тысяч строк и более)Фильтруйте данные на сервере и передавайте только нужную часть через хранилище

Проверка результата и типичные ошибки

После реализации любого из способов проверьте, что данные действительно дошли до клиента. Для реквизита формы достаточно вывести таблицу на форму или проверить количество строк в клиентской процедуре: ЭтаФорма.ТаблицаТоваров.Количество(). Для массива структур — аналогично через Количество() и обращение к первому элементу.

Для временного хранилища проверку выполняют на сервере: получите данные обратно через ПолучитьИзВременногоХранилища(Адрес) и убедитесь, что тип результата — «ТаблицаЗначений» и строки на месте. Если функция вернула Неопределено — чаще всего истёк срок жизни хранилища или не был передан идентификатор формы.

Типичные ошибки
01
Возврат ТаблицыЗначений из серверной функции напрямую — ошибка сериализации при передаче на клиент
02
Помещение в хранилище без УникальныйИдентификаторФормы — данные удаляются сразу после серверного вызова
03
Использование метода Выгрузить() у таблицы формы на клиенте — метод недоступен в клиентском контексте
04
Передача в массиве структур несериализуемых значений (вложенных таблиц, COM-объектов) — падение при вызове
05
Передача всей таблицы без фильтрации — тяжёлый трафик и зависание тонкого клиента

Отдельная частая проблема — попытка изменить реквизит формы «напрямую» на сервере через обращение к коллекции строк. Для реквизита типа «ТаблицаЗначений» на сервере доступна модификация через ДанныеФормы в объектную модель только через РеквизитФормыВЗначение(), изменение и обратную загрузку. Прямое обращение работает, но с ограничениями, и для массовой загрузки всегда эффективнее связка ЗначениеВРеквизитФормы().

Контрольные точки

Как проверить результат

Количество строк на клиенте
Норма

Совпадает с количеством строк результата запроса на сервере

Тревожный признак

Ноль строк или меньше ожидаемого — данные не загружены или потеряны

Тип данных после ПолучитьИзВременногоХранилища
Норма

ТаблицаЗначений с нужными колонками

Тревожный признак

Неопределено — хранилище очищено, проверьте идентификатор формы

Значения в массиве структур
Норма

Поля доступны через точку, типы значений корректны

Тревожный признак

Ошибка обращения к полю — имя колонки не попало в структуру

FAQ: частые вопросы

Можно ли передать таблицу значений в фоновое задание и обратно?

В фоновое задание таблица передаётся через параметры метода Выполнить() только после сериализации — например, как массив структур. Результат фонового задания возвращается через временное хранилище: адрес помещается в параметры задания, а после завершения вызывающая сторона забирает данные по этому адресу на сервере.

Чем отличается ЗначениеВРеквизитФормы от ЗначениеВДанныеФормы?

ЗначениеВРеквизитФормы — метод формы, работающий с реквизитом по имени. ЗначениеВДанныеФормы — глобальный метод, принимающий объект ДанныеФормы. Для реквизита-таблицы обычно используют первый; второй нужен при работе с вложенными структурами данных формы.

Как передать таблицу с динамическим набором колонок на форму?

Сначала программно создайте реквизиты формы: сформируйте массив объектов РеквизитФормы с именами и типами колонок, вызовите ИзменитьРеквизиты(), затем добавьте элементы формы для отображения колонок. После этого загрузите данные через ЗначениеВРеквизитФормы.

Почему на тонком клиенте таблица передаётся медленно?

При каждом серверном вызове реквизиты формы синхронизируются между клиентом и сервером. Чем больше строк в таблице-реквизите, тем тяжелее трафик. Решение — разбивать данные на порции, фильтровать на сервере или отказаться от реквизита формы в пользу динамического списка, который загружает данные постранично.

Можно ли сериализовать таблицу через ЗначениеВСтрокуВнутр?

Да, функция ЗначениеВСтрокуВнутр() преобразует таблицу во внутреннее строковое представление, которое передаётся как обычная строка. На клиенте строка восстанавливается через ЗначениеИзСтрокиВнутр(). Способ работает, но считается устаревшим для обмена клиент-сервер: строка громоздкая, формат недокументирован, и в большинстве сценариев удобнее массив структур или хранилище.

Что быстрее — массив структур или временное хранилище?

Для небольших таблиц (сотни строк) разница незаметна. При тысячах строк массив структур тратит время на создание структур для каждой строки и передаёт весь объём на клиент, а хранилище оставляет данные на сервере и передаёт только адрес. Для крупных таблиц хранилище предпочтительнее.

Итог

Что важно запомнить

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