Как передать результат выборки запроса с сервера на клиент в 1С 8.3?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В процессе разработки на платформе 1С:Предприятие 8.3 начинающие (а иногда и опытные) программисты сталкиваются с архитектурным ограничением: объекты типа Запрос, РезультатЗапроса и ВыборкаИзРезультатаЗапроса существуют только на сервере. Попытка передать их напрямую на клиент (в процедуру &НаКлиенте) приведет к ошибке отображения или исключению «Данный тип не может быть передан на клиент». Давайте подробно разберем, как правильно организовать обмен данными в управляемых формах.

Почему нельзя передать выборку напрямую?

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

Решение 1: Заполнение списка выбора на сервере (Контекстный вызов)

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

Поскольку процедура &НаСервере имеет доступ к реквизитам формы, мы можем напрямую обратиться к свойству СписокВыбора элемента формы.

Пример реализации:


&НаСервере
Процедура ЗаполнитьСписокНаСервере()
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   Номенклатура.Ссылка КАК Ссылка,
        |   Номенклатура.Наименование КАК Наименование
        |ИЗ
        |   Справочник.Номенклатура КАК Номенклатура";
    
    Выборка = Запрос.Выполнить().Выбрать();
    
    // Очищаем старый список перед заполнением
    Элементы.ПолеНоменклатура.СписокВыбора.Очистить();
    
    Пока Выборка.Следующий() Цикл
        Элементы.ПолеНоменклатура.СписокВыбора.Добавить(Выборка.Ссылка, Выборка.Наименование);
    КонецЦикла;
КонецПроцедуры

Преимущество: Это максимально быстрый способ, так как платформа сама оптимизирует передачу СпискаЗначений между сервером и клиентом.

Решение 2: Преобразование таблицы значений в массив структур (Неконтекстный вызов)

Выясним причину, почему иногда требуется передать данные именно в переменную на клиенте. Например, если вы используете функцию &НаСервереБезКонтекста для повышения производительности. В этом случае у вас нет доступа к элементам формы, и данные нужно вернуть как результат функции.

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

Рассмотрим пример функции преобразования:


&НаСервереБезКонтекста
Функция ПолучитьДанныеДляКлиента(НоменклатураСсылка)
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   ПродуктыОстатки.Партия КАК Партия,
        |   ПродуктыОстатки.КоличествоОстаток КАК Остаток
        |ИЗ
        |   РегистрНакопления.ПродуктыНаСкладах.Остатки(, Номенклатура = &Номенклатура) КАК ПродуктыОстатки";
    
    Запрос.УстановитьПараметр("Номенклатура", НоменклатураСсылка);
    Таблица = Запрос.Выполнить().Выгрузить();
    
    МассивРезультат = Новый Массив;
    
    // Формируем строку колонок для быстрого создания структур
    ИменаКолонок = "";
    Для Каждого Колонка Из Таблица.Колонки Цикл
        ИменаКолонок = ИменаКолонок + ?(ИменаКолонок = "", "", ",") + Колонка.Имя;
    КонецЦикла;
    
    Для Каждого Строка Из Таблица Цикл
        НоваяСтруктура = Новый Структура(ИменаКолонок);
        ЗаполнитьЗначенияСвойств(НоваяСтруктура, Строка);
        МассивРезультат.Добавить(НоваяСтруктура);
    КонецЦикла;
    
    Возврат МассивРезультат;
КонецФункции

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

Решение 3: Использование временного хранилища

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

  1. На сервере вы помещаете таблицу или выборку во временное хранилище с помощью метода ПоместитьВоВременноеХранилище().
  2. Метод возвращает уникальный Адрес (строку).
  3. Этот адрес передается на клиент.
  4. Когда данные снова понадобятся на сервере (например, для другого отчета), клиент передает адрес обратно, и сервер извлекает объект.

Важно: Помните, что данные во временном хранилище живут только в течение сеанса или пока живет форма (если передан уникальный идентификатор формы).

Решение 4: Метод ЗначениеВРеквизитФормы

Рассмотрим ситуацию, когда результат запроса нужно отобразить в таблице на форме. Вместо того чтобы вручную перебирать строки, эффективнее использовать встроенные методы платформы. Если у вас на форме есть реквизит с типом ТаблицаЗначений, мы можем сделать следующее:


&НаСервере
Процедура ЗагрузитьДанныеВТаблицуНаФорме()
    Запрос = Новый Запрос("ВЫБРАТЬ ... "); // Ваш текст запроса
    ТаблицаРезультат = Запрос.Выполнить().Выгрузить();
    
    // Преобразуем таблицу значений в реквизит формы "Объект.Товары"
    ЗначениеВРеквизитФормы(ТаблицаРезультат, "Объект.Товары");
КонецПроцедуры

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

Решение 5: Выгрузка отдельной колонки

Если для формирования списка выбора вам нужно только одно поле (например, только ссылки на документы), не стоит создавать массив структур. Проанализируем метод ВыгрузитьКолонку():


&НаСервереБезКонтекста
Функция ПолучитьМассивСсылок()
    Запрос = Новый Запрос("ВЫБРАТЬ Ссылка ИЗ Справочник.Склады");
    Таблица = Запрос.Выполнить().Выгрузить();
    
    // Возвращает массив, содержащий только значения из колонки "Ссылка"
    Возврат Таблица.ВыгрузитьКолонку("Ссылка"); 
КонецФункции

Массив простых ссылок — это самый «легкий» тип данных для передачи между контекстами.

Рекомендации по оптимизации

Подведем итог и выделим важные моменты, которые помогут избежать ошибок:

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

← На главную