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