При переходе с обычных форм или толстого клиента на управляемое приложение разработчики часто сталкиваются с ситуацией: код, который без сбоев отрабатывает в толстом клиенте или в процессе отладки, внезапно падает с ошибкой в режиме тонкого клиента при вызове метода ПолучитьОбъект() или попытке прямого обращения к реквизитам ссылки через точку. Разберем по шагам, почему возникает эта ошибка, как устроено разделение контекстов выполнения и как правильно перенести логику на сервер.
Проанализируем механизм работы платформы 1С:Предприятие 8.3 в управляемом режиме. В тонком клиенте исполняется только клиентский код интерфейса. Синтакс-помощник четко определяет доступность метода ПолучитьОбъект() для ссылочных типов:
Доступность метода: Сервер, толстый клиент, внешнее соединение, мобильное приложение (сервер).
Выясним причину такого поведения: тонкий клиент не хранит в оперативной памяти полные объектные данные базы (шапку, табличные части, движения) и не имеет прямого доступа к СУБД. На клиенте ссылка представляет собой лишь облегченный идентификатор. Попытка вызвать метод ПолучитьОбъект() непосредственно в клиентской процедуре (с директивой &НаКлиенте) приводит к исключению времени выполнения, так как данный метод в тонком клиенте просто отсутствует.
Если нам действительно необходимо получить объект целиком (например, для его изменения, блокировки или программной записи), вызов метода ПолучитьОбъект() необходимо перенести в серверную процедуру или функцию. Рассмотрим пример передачи ссылки с клиента на сервер:
&НаКлиенте
Процедура ОбработатьДокументКлиент(Команда)
// Передаем ссылку из реквизита формы в серверную процедуру
ИзменитьДокументНаСервере(Объект.Док);
КонецПроцедуры
&НаСервереБезКонтекста
Процедура ИзменитьДокументНаСервере(СсылкаНаДокумент)
Если Не ЗначениеЗаполнено(СсылкаНаДокумент) Тогда
Возврат;
КонецЕсли;
// На сервере метод ПолучитьОбъект() доступен полностью
ДокОбъект = СсылкаНаДокумент.ПолучитьОбъект();
ДокОбъект.Комментарий = "Обработано регламентной процедурой";
ДокОбъект.Записать(РежимЗаписиДокумента.Запись);
КонецПроцедуры
Часто метод ПолучитьОбъект() ошибочно вызывают только для того, чтобы прочитать реквизиты документа (номер, дату, контрагента) и вывести их пользователю. Создание тяжелого серверного объекта для простого чтения данных крайне неоптимально, так как считываются все табличные части документа.
Посмотрим на более производительные варианты решения этой задачи:
&НаКлиенте
Процедура ВывестиДанныеДокумента(Команда)
// Получаем готовую строку с сервера
ИнформацияОДоке = СформироватьСтроку(Объект.Док);
ПоказатьОповещениеПользователя("Данные документа", , ИнформацияОДоке);
КонецПроцедуры
&НаСервереБезКонтекста
Функция СформироватьСтроку(СсылкаНаДок)
Если Не ЗначениеЗаполнено(СсылкаНаДок) Тогда
Возврат "Документ не выбран";
КонецЕсли;
// На сервере можно читать реквизиты напрямую через точку ссылки
Возврат "Документ № " + СсылкаНаДок.Номер + " от " + Формат(СсылкаНаДок.Дата, "ДФ=dd.MM.yyyy");
КонецФункции
Разберем важный нюанс при вызове серверных процедур из управляемой формы. Существуют две основные директивы компиляции для серверных вызовов:
Если внутри серверной процедуры вам не требуется менять состав элементов или специфические реквизиты формы, всегда объявляйте методы с директивой &НаСервереБезКонтекста и передавайте нужные ссылки в параметрах.
Рассмотрим случай, когда требуется вызвать метод модуля объекта самой обработки. В управляемой форме реквизит Объект имеет тип ДанныеФормыСтруктура, а не ОбработкаОбъект. Чтобы превратить данные формы в прикладной объект на сервере, используем специальный метод платформы РеквизитФормыВЗначение():
&НаСервере
Процедура ВыполнитьАлгоритмОбработкиНаСервере()
// Преобразуем реквизит формы в прикладной объект ОбработкаОбъект
ОбработкаОбъект = РеквизитФормыВЗначение("Объект");
// Вызываем экспортную процедуру из модуля объекта обработки
ОбработкаОбъект.ВыполнитьДействие();
// Если алгоритм изменил реквизиты обработки, возвращаем данные в форму
ЗначениеВРеквизитФормы(ОбработкаОбъект, "Объект");
КонецПроцедуры
Чтобы исключить падения программы в тонком клиенте еще на этапе написания кода, настроим автоматическую проверку конфигурации:
Ctrl + F7) платформа сразу укажет на недопустимые для тонкого клиента вызовы методов до запуска режима 1С:Предприятие.