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

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

1С: как передать результат запроса с серверной процедуры на клиент

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

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

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

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

Почему результат запроса нельзя вернуть напрямую

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

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

Способ 1. Массив структур — универсальный вариант

Самый распространённый приём: на сервере обойти выборку запроса и собрать массив структур, где каждая структура описывает одну строку. Такой массив свободно возвращается на клиент и там перебирается в цикле.

&НаСервере

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

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

Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ 100 Номенклатура.Ссылка КАК Ссылка,

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

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

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

Выборка = Результат.Выбрать();

МассивДанных = Новый Массив;

Пока Выборка.Следующий() Цикл

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

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

МассивДанных.Добавить(Строка);

КонецЦикла;

Возврат МассивДанных;

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

&НаКлиенте

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

Данные = ПолучитьДанныеНаСервере();

Для Каждого Строка Из Данные Цикл

Сообщить(Строка.Наименование);

КонецЦикла;

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

Метод ЗаполнитьЗначенияСвойств копирует поля выборки в структуру, если имена свойств совпадают с именами колонок запроса. Это избавляет от ручного перечисления полей, но требует следить за соответствием имён.

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

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

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

&НаСервере

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

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

Запрос.Текст = "ВЫБРАТЬ Товар, Количество ИЗ РегистрНакопления.Остатки.Остатки";

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

Товары.Загрузить(ТаблицаРезультат);

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

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

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

Способ 3. JSON для обмена и больших данных

Когда данные нужно передать не только на клиент формы, но и во внешнюю систему, или когда структура строк заранее неизвестна, результат удобно сериализовать в JSON. На сервере формируется массив структур или соответствий, затем он преобразуется в строку через ЗаписьJSON.

&НаСервере

Функция ДанныеВJSONНаСервере()

Запрос = Новый Запрос("ВЫБРАТЬ Ссылка, Код ИЗ Справочник.Контрагенты");

Выборка = Запрос.Выполнить().Выбрать();

Массив = Новый Массив;

Пока Выборка.Следующий() Цикл

Массив.Добавить(Новый Структура("Код", Выборка.Код));

КонецЦикла;

Запись = Новый ЗаписьJSON;

Запись.УстановитьСтроку();

ЗаписатьJSON(Запись, Массив);

Возврат Запись.Закрыть();

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

На клиенте строка разбирается через ПрочитатьJSON. Учитывайте особенность: ссылки в JSON сериализуются неочевидным образом, поэтому для обмена лучше передавать строковое представление уникального идентификатора или код элемента, а ссылку восстанавливать на сервере при необходимости.

Способ 4. Хранилище значения и временное хранилище

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

&НаСервере

Функция ПоместитьВХранилищеНаСервере()

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

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

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

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

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

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

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

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

Универсально и просто; подходит до нескольких тысяч строк, дальше начинает тормозить передача по сети.

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

Лучший вариант для отображения в таблице формы; не подходит, если клиенту нужна только часть данных.

JSON

Незаменим для интеграций; избыточен для внутренней передачи внутри формы.

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

Единственный разумный вариант для очень больших результатов; требует дисциплины очистки.

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

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

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

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

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

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

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

Строк меньше или массив пуст — проверяйте условия запроса и заполнение структуры

Типы значений
Норма

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

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

Всё превратилось в строки — признак лишней сериализации в JSON

Время выполнения
Норма

Вызов занимает секунды на типовом объёме

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

Десятки секунд — сокращайте выборку или переходите на хранилище

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

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

Итог

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

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

Частые вопросы

Можно ли вернуть с сервера сам объект Запрос или РезультатЗапроса?

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

Что быстрее: массив структур или таблица значений?

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

Как передать результат запроса в другую форму?

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

Почему после передачи ссылки превратились в строки?

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

Работает ли передача в тонком и веб-клиенте?

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

Как ограничить объём передаваемых данных?

Используйте конструкцию ВЫБРАТЬ ПЕРВЫЕ в тексте запроса, накладывайте отборы через параметры, выбирайте только необходимые поля вместо звёздочки. Для произвольного просмотра больших списков реализуйте постраничную загрузку: сервер возвращает очередную порцию по смещению, а клиент запрашивает следующую по мере прокрутки.