Почему метод ПолучитьОбъект() не работает в тонком клиенте на управляемых формах и как это исправить?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При переходе с обычных форм или толстого клиента на управляемое приложение разработчики часто сталкиваются с ситуацией: код, который без сбоев отрабатывает в толстом клиенте или в процессе отладки, внезапно падает с ошибкой в режиме тонкого клиента при вызове метода ПолучитьОбъект() или попытке прямого обращения к реквизитам ссылки через точку. Разберем по шагам, почему возникает эта ошибка, как устроено разделение контекстов выполнения и как правильно перенести логику на сервер.

Причина ошибки: ограничения доступности методов и типов данных

Проанализируем механизм работы платформы 1С:Предприятие 8.3 в управляемом режиме. В тонком клиенте исполняется только клиентский код интерфейса. Синтакс-помощник четко определяет доступность метода ПолучитьОбъект() для ссылочных типов:

Доступность метода: Сервер, толстый клиент, внешнее соединение, мобильное приложение (сервер).

Выясним причину такого поведения: тонкий клиент не хранит в оперативной памяти полные объектные данные базы (шапку, табличные части, движения) и не имеет прямого доступа к СУБД. На клиенте ссылка представляет собой лишь облегченный идентификатор. Попытка вызвать метод ПолучитьОбъект() непосредственно в клиентской процедуре (с директивой &НаКлиенте) приводит к исключению времени выполнения, так как данный метод в тонком клиенте просто отсутствует.

Решение 1. Перенос получения объекта на сторону сервера

Если нам действительно необходимо получить объект целиком (например, для его изменения, блокировки или программной записи), вызов метода ПолучитьОбъект() необходимо перенести в серверную процедуру или функцию. Рассмотрим пример передачи ссылки с клиента на сервер:


&НаКлиенте
Процедура ОбработатьДокументКлиент(Команда)
    // Передаем ссылку из реквизита формы в серверную процедуру
    ИзменитьДокументНаСервере(Объект.Док);
КонецПроцедуры

&НаСервереБезКонтекста
Процедура ИзменитьДокументНаСервере(СсылкаНаДокумент)
    Если Не ЗначениеЗаполнено(СсылкаНаДокумент) Тогда
        Возврат;
    КонецЕсли;
    
    // На сервере метод ПолучитьОбъект() доступен полностью
    ДокОбъект = СсылкаНаДокумент.ПолучитьОбъект();
    ДокОбъект.Комментарий = "Обработано регламентной процедурой";
    ДокОбъект.Записать(РежимЗаписиДокумента.Запись);
КонецПроцедуры

Решение 2. Чтение реквизитов документа без создания объекта

Часто метод ПолучитьОбъект() ошибочно вызывают только для того, чтобы прочитать реквизиты документа (номер, дату, контрагента) и вывести их пользователю. Создание тяжелого серверного объекта для простого чтения данных крайне неоптимально, так как считываются все табличные части документа.

Посмотрим на более производительные варианты решения этой задачи:

  1. Обращение через точку на сервере: На стороне сервера платформа позволяет обращаться к реквизитам ссылки напрямую через точку.
  2. Использование серверной функции для сборки строки: Получаем данные на сервере и возвращаем на клиент уже готовый результат.

&НаКлиенте
Процедура ВывестиДанныеДокумента(Команда)
    // Получаем готовую строку с сервера
    ИнформацияОДоке = СформироватьСтроку(Объект.Док);
    ПоказатьОповещениеПользователя("Данные документа", , ИнформацияОДоке);
КонецПроцедуры

&НаСервереБезКонтекста
Функция СформироватьСтроку(СсылкаНаДок)
    Если Не ЗначениеЗаполнено(СсылкаНаДок) Тогда
        Возврат "Документ не выбран";
    КонецЕсли;
    
    // На сервере можно читать реквизиты напрямую через точку ссылки
    Возврат "Документ № " + СсылкаНаДок.Номер + " от " + Формат(СсылкаНаДок.Дата, "ДФ=dd.MM.yyyy");
КонецФункции

Решение 3. Оптимизация контекста: &НаСервере vs &НаСервереБезКонтекста

Разберем важный нюанс при вызове серверных процедур из управляемой формы. Существуют две основные директивы компиляции для серверных вызовов:

  1. &НаСервере: При вызове такой процедуры все данные формы (реквизиты, списки, таблицы) упаковываются (сериализуются), передаются по сети на сервер, а затем передаются обратно на клиент. Это создает лишний трафик и замедляет работу.
  2. &НаСервереБезКонтекста: Контекст формы не передается на сервер. Передаются только параметры, указанные в вызове процедуры или функции. Это существенно экономит ресурсы сети и ускоряет отклик интерфейса.

Если внутри серверной процедуры вам не требуется менять состав элементов или специфические реквизиты формы, всегда объявляйте методы с директивой &НаСервереБезКонтекста и передавайте нужные ссылки в параметрах.

Решение 4. Работа с объектом самой обработки на управляемой форме

Рассмотрим случай, когда требуется вызвать метод модуля объекта самой обработки. В управляемой форме реквизит Объект имеет тип ДанныеФормыСтруктура, а не ОбработкаОбъект. Чтобы превратить данные формы в прикладной объект на сервере, используем специальный метод платформы РеквизитФормыВЗначение():


&НаСервере
Процедура ВыполнитьАлгоритмОбработкиНаСервере()
    // Преобразуем реквизит формы в прикладной объект ОбработкаОбъект
    ОбработкаОбъект = РеквизитФормыВЗначение("Объект");
    
    // Вызываем экспортную процедуру из модуля объекта обработки
    ОбработкаОбъект.ВыполнитьДействие();
    
    // Если алгоритм изменил реквизиты обработки, возвращаем данные в форму
    ЗначениеВРеквизитФормы(ОбработкаОбъект, "Объект");
КонецПроцедуры

Как предотвратить подобные ошибки на этапе разработки?

Чтобы исключить падения программы в тонком клиенте еще на этапе написания кода, настроим автоматическую проверку конфигурации:

  1. Откроем в конфигураторе меню Конфигурация — Проверка конфигурации.
  2. Установим флаги синтаксической проверки для всех режимов: Тонкий клиент, Сервер, Внешнее соединение.
  3. При выполнении проверки синтаксиса текущего модуля (сочетание клавиш Ctrl + F7) платформа сразу укажет на недопустимые для тонкого клиента вызовы методов до запуска режима 1С:Предприятие.
← На главную