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