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

Программист 1С v8.3 (Управляемые формы) Бухгалтерский учет
← На главную

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

Проблема 1: Ошибка обращения к ВладелецФормы на сервере

Рассмотрим ситуацию, когда разработчик пытается получить дату из формы-владельца непосредственно в серверном коде. В коде автора сообщения мы видим попытку обращения: Запрос.УстановитьПараметр("НачПериода", ВладелецФормы.Объект.Дата...). Это приводит к ошибке "Свойство недоступно на сервере".

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

Давайте изменим структуру вызова. На клиенте мы подготовим данные, а на сервере просто примем их:


&НаКлиенте
Процедура ВыполнитьКоманду(Команда)
    
    // Получаем данные на клиенте, где ВладелецФормы доступен
    ДатаДокумента = ВладелецФормы.Объект.Дата;
    
    // Передаем дату как параметр в серверную функцию
    ДанныеДляЗаполнения = ПолучитьДанныеНаСервере(ДатаДокумента);
    
    // Обработка полученных данных...
    
КонецПроцедуры

Проблема 2: Невозможность передачи Выборки на клиент

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

Разберем по шагам, как передать данные запроса. Для этого нам необходимо выгрузить результат запроса в универсальную коллекцию, которая умеет "путешествовать" между сервером и клиентом. Лучше всего для этого подходит Массив структур.

Рассмотрим пример реализации серверной функции, которая корректно возвращает данные:


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

Оптимизация работы с датами в запросе

Посмотрим на пример из Сообщения 2. Вместо того чтобы вычислять границы периода на клиенте сложными формулами типа Дата - 90 * (3600 * 24), гораздо эффективнее использовать встроенные функции языка запросов. Это сделает код чище и надежнее.

Проанализируем ситуацию: если нам нужно получить данные за последние 90 дней от даты документа, мы можем передать в запрос только одну дату, а периоды рассчитать внутри текста запроса:


// В тексте запроса внутри параметров виртуальной таблицы
| РегистрБухгалтерии.Хозрасчетный.ДвиженияССубконто(
|    ДОБАВИТЬКДАТЕ(&ДатаДокумента, ДЕНЬ, -90),
|    &ДатаДокумента,
|    ...
| )

Это избавляет нас от лишних вычислений на стороне клиента и гарантирует, что СУБД обработает даты максимально корректно.

Эффективное заполнение таблицы на клиенте

После того как мы вернули массив структур на клиент, нам нужно заполнить таблицу в форме-владельце. Рассмотрим, как это сделать правильно, минимизируя количество обращений к интерфейсу.


&НаКлиенте
Процедура ВыполнитьКоманду(Команда)
    
    Данные = ПолучитьДанныеНаСервере(ВладелецФормы.Объект.Дата);
    
    // Получаем доступ к табличной части формы-владельца
    ТаблицаТовары = ВладелецФормы.Объект.Товары;
    
    Для Каждого СтрокаДанных Из Данные Цикл
        НоваяСтрока = ТаблицаТовары.Добавить();
        ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаДанных);
    КонецЦикла;
    
КонецПроцедуры

Обратите внимание на использование функции ЗаполнитьЗначенияСвойств. Это стандартный и быстрый способ перенести данные из полей структуры в одноименные поля строки таблицы.

Рекомендации по повышению производительности

Проанализировав исходный код темы, дадим несколько важных советов по оптимизации:

  1. Использование ССЫЛКА вместо ТИП: В запросе автора использовалась конструкция ТИПЗНАЧЕНИЯ(Регистратор) = ТИП(Документ.ПередачаТоваров). Для повышения скорости работы запроса в 1С рекомендуется использовать оператор ССЫЛКА: Регистратор ССЫЛКА Документ.ПередачаТоваров.
  2. Внеконтекстные вызовы: Используйте директиву &НаСервереБезКонтекста везде, где это возможно. Это значительно ускоряет работу приложения в тонком клиенте, так как платформа не пересылает данные всей текущей формы на сервер и обратно.
  3. Минимизация циклов на клиенте: Если строк очень много (более нескольких сотен), заполнение таблицы в цикле на клиенте может вызвать "подтормаживание" интерфейса. В таких случаях лучше передать управление на сервер формы-владельца и выполнить заполнение там.

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

← На главную