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