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