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