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

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

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

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

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

Выбор способа зависит от контекста: объёма данных, того, нужна ли таблица на клиенте для редактирования или только для чтения, работаете ли вы с формой или вне контекста формы. Ниже разобраны все рабочие варианты с примерами кода, их ограничения и ситуации, в которых каждый из них оправдан.

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

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

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

Если попытаться вернуть таблицу значений из серверной функции, вызванной с клиента, платформа выбросит исключение вида «Ошибка при вызове метода контекста» с указанием на недопустимость передачи значения. Та же проблема возникает и в обратную сторону — при передаче таблицы значений с клиента на сервер в качестве параметра.

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

Способ 1. Хранилище значения

Самый простой и надёжный вариант — упаковать таблицу значений в объект «ХранилищеЗначения». Этот тип спокойно передаётся между клиентом и сервером, а на клиенте таблицу можно извлечь обратно методом Получить().

На сервере код выглядит так:

&НаСервереБезКонтекста

Функция ПолучитьТаблицуНаСервере()

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

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

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

// ... заполнение таблицы из запроса или программно

Возврат Новый ХранилищеЗначения(ТЗ, Новый СжатиеДанных(9));

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

На клиенте:

&НаКлиенте

Процедура ЗагрузитьДанные(Команда)

Хранилище = ПолучитьТаблицуНаСервере();

ТЗ = Хранилище.Получить();

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

Сообщить(СтрокаТЗ.Номенклатура);

КонецЦикла;

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

Обратите внимание на параметр сжатия: для больших таблиц сжатие заметно уменьшает объём передаваемых данных по сети. Недостаток способа — на клиенте таблица приходит «как есть», без возможности привязки к элементу формы напрямую, и для больших объёмов сериализация всё равно создаёт накладные расходы.

Способ 2. Сериализация через ЗначениеВСтрокуВнутр или СериализаторXDTO

Альтернатива хранилищу — преобразовать таблицу в строку. Метод ЗначениеВСтрокуВнутр() возвращает внутреннее строковое представление объекта, которое передаётся на клиент как обычная строка, а там восстанавливается методом ЗначениеИзСтрокиВнутр().

&НаСервереБезКонтекста

Функция ПолучитьТаблицуСтрокой()

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

// ... заполнение

Возврат ЗначениеВСтрокуВнутр(ТЗ);

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

&НаКлиенте

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

СтрокаДанных = ПолучитьТаблицуСтрокой();

ТЗ = ЗначениеИзСтрокиВнутр(СтрокаДанных);

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

Второй вариант сериализации — СериализаторXDTO с методами ЗаписатьXML/ПрочитатьXML. Он даёт XML-представление, которое удобно, если данные нужно не только передать на клиент, но и сохранить или обменяться с внешней системой. Для простой задачи «сервер → клиент» это избыточно: сериализация в XML медленнее и даёт больший объём, чем ЗначениеВСтрокуВнутр.

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

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

&НаСервере

Функция СформироватьДанныеНаСервере()

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

// ... заполнение

Возврат ПоместитьВоВременноеХранилище(ТЗ, УникальныйИдентификатор);

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

Второй параметр — УникальныйИдентификатор формы — важен: он привязывает данные к времени жизни формы, и хранилище не будет очищено до её закрытия. Без привязки данные живут ограниченное время и могут быть удалены платформой.

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

Способ 4. Массив структур

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

&НаСервереБезКонтекста

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

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

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

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

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

КонецЦикла;

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

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

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

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

КонецЦикла;

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

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

Обратное преобразование — из массива структур в таблицу значений — делается созданием колонок по ключам первой структуры и добавлением строк в цикле. Минус подхода: теряются типы колонок (в структуре хранятся просто значения), а для очень широких таблиц код заполнения работает медленнее, чем бинарная сериализация. Зато такой массив легко отлаживать, перебирать на клиенте и даже передавать дальше в веб-сервисы или JSON.

Сравнение вариантов

ХранилищеЗначения

Простой код, сохраняет типы и структуру таблицы. Ограничение: весь объект сериализуется целиком, нет контроля над форматом.

ЗначениеВСтрокуВнутр

Компактная строка, удобно кэшировать. Ограничение: внутренний формат платформы, не подходит для обмена с внешними системами.

Временное хранилище

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

Массив структур

Прозрачная структура, легко отлаживать и конвертировать в JSON. Ограничение: теряются типы колонок, больше ручного кода.

Реквизит формы

Платформа переносит данные сама, сразу доступно отображение в таблице формы. Ограничение: работает только в контексте формы.

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

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

На сервере таблица значений загружается в реквизит через значение в данные формы:

&НаСервере

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

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

// ... заполнение из запроса

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

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

На клиенте с данными работают как с коллекцией ДанныеФормыКоллекция: доступны перебор строк, добавление, удаление, поиск. Платформа сама синхронизирует содержимое между клиентом и сервером при серверных вызовах — разработчику не нужно думать о сериализации. Это предпочтительный сценарий для любых данных, которые отображаются или редактируются в форме.

Порядок действий для передачи через хранилище значения
  1. 1
    Создайте на сервере функцию, которая формирует и заполняет таблицу значений
  2. 2
    Оберните таблицу: Новый ХранилищеЗначения(ТЗ, Новый СжатиеДанных(9)) и верните из функции
  3. 3
    На клиенте вызовите серверную функцию и получите хранилище
  4. 4
    Извлеките таблицу методом Хранилище.Получить()
  5. 5
    Проверьте результат: переберите строки циклом и убедитесь, что колонки и данные на месте

Частые ошибки и их диагностика

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

Вторая ошибка — передача таблицы, содержащей несериализуемые значения в ячейках. Например, если в колонке лежат объекты типа «РезультатЗапроса» или COM-объекты, сериализация упадёт даже внутри хранилища значения. Перед упаковкой убедитесь, что в ячейках только допустимые типы: примитивы, ссылки, даты, структуры.

Третья ошибка — использование временного хранилища без привязки к форме и получение пустых данных при повторном обращении. Если ПоместитьВоВременноеХранилище вызван без второго параметра, данные могут быть удалены сборщиком до момента извлечения. Всегда передавайте УникальныйИдентификатор формы.

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

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

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

После передачи проверьте три вещи: количество строк совпадает с серверной таблицей, имена колонок на месте, значения ключевых полей (даты, ссылки, числа) имеют корректные типы. Проще всего это сделать отладчиком, поставив точку останова на клиенте сразу после получения данных, либо вывести в цикле несколько первых строк через Сообщить().

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

Маршрут решения

Как выбрать действие

Данные нужно показать в таблице на управляемой формеСоздайте реквизит формы типа ТаблицаЗначений и заполняйте его через ЗначениеВРеквизитФормы
Таблица нужна на клиенте как объект для обхода в кодеВерните её с сервера в ХранилищеЗначения и извлеките методом Получить()
Таблица формируется фоновым заданием или очень большаяПоместите её во временное хранилище с привязкой к форме и извлекайте на сервере
Данные дальше уйдут в JSON, HTTP-сервис или на веб-клиент с ограничениямиПреобразуйте таблицу в массив структур
Контрольные точки

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

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

Совпадает с количеством строк таблицы на сервере

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

Строк меньше или таблица пустая — проверяйте сериализацию и привязку хранилища

Типы значений в колонках
Норма

Даты остаются датами, ссылки — ссылками, числа — числами

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

Все значения стали строками — вероятно, использован массив структур без восстановления типов

Скорость вызова
Норма

Серверный вызов завершается без заметной паузы

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

Задержка в секунды — объём данных слишком велик, нужен другой способ

FAQ

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

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

Чем отличается ЗначениеВСтрокуВнутр от сериализатора XDTO?

ЗначениеВСтрокуВнутр использует внутренний бинарно-ориентированный формат платформы — он компактнее и быстрее, но читается только самой платформой. СериализаторXDTO даёт XML, который можно передать внешней системе, но работает медленнее и требует, чтобы тип был известен модели XDTO.

Почему после извлечения из временного хранилища данные пустые?

Чаще всего хранилище было создано без привязки к форме (без параметра УникальныйИдентификатор), и платформа очистила данные. Также проверьте, что адрес не используется повторно после того, как данные уже извлечены с удалением.

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

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

Что делать, если таблица содержит колонку с типом «Картинка» или другим сложным типом?

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

Есть ли ограничение на размер передаваемой таблицы?

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

Итог

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

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