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