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