Почему нельзя вызывать методы объекта напрямую из реквизита формы и в чем разница между РеквизитФормыВЗначение и ПолучитьОбъект в 1С

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

При переходе на управляемый интерфейс 1С:Предприятия 8 многие разработчики сталкиваются с непониманием того, как устроен реквизит Объект на управляемой форме. Возникает естественный вопрос: почему для вызова метода документа или справочника недостаточно обратится к Объект.ИмяМетода(), а требуется использовать функцию РеквизитФормыВЗначение() или метод ПолучитьОбъект()?

В этой статье мы подробно разберем архитектуру работы с данными на управляемых формах, проанализируем разницу между прикладными объектами в памяти и легкими структурами данных формы, а также рассмотрим лучшие практики выполнения серверных операций.

В чем разница между типом ДанныеФормыСтруктура и прикладным объектом

Рассмотрим причину, по которой методы модуля объекта недоступны напрямую из реквизита формы. На клиенте и на сервере реквизит управляемой формы Объект имеет тип ДанныеФормыСтруктура, а не прикладной тип ДокументОбъект или СправочникОбъект.

Тип ДанныеФормыСтруктура представляет собой специальный «облегченный» контейнер данных, оптимизированный для быстрой передачи по сети между клиентом и сервером. В нем содержатся только значения реквизитов и табличных частей, необходимых для отображения в интерфейсе. Из-за такой оптимизации данный тип не содержит в себе:

  1. Методов модуля объекта (экспортных процедур и функций, написанных разработчиком).
  2. Системных методов прикладного объекта (например, ПроверитьЗаполнение(), Записать(), УстановитьПометкуУдаления()).
  3. Обработчиков событий документа или справочника (таких как ОбработкаПроведения()).

Для выполнения бизнес-логики, заложенной в модуле объекта, несохраненные данные формы необходимо предварительно преобразовать в прикладной объект в памяти сервера.

Вариант 1: Использование РеквизитФормыВЗначение и ЗначениеВРеквизитФормы

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


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

Выясним, что происходит при каждом шаге выполнения этого кода:

  1. Вызов РеквизитФормыВЗначение("Объект") считывает текущую структуру ДанныеФормыСтруктура и создает в оперативной памяти сервера экземпляр типа ДокументОбъект. Все несохраненные изменения, которые пользователь внес на форме, попадают в этот новый объект.
  2. На объекте ДокументОбъект вызывают необходимые прикладные методы.
  3. Вызов ЗначениеВРеквизитФормы(ДокументОбъект, "Объект") перезаписывает свойства и табличные части формы обновленными данными из объекта. После этого форма переходит в состояние Модифицированность = Истина.

Важный момент: Данный метод работает в контексте формы и доступен только в процедурах с директивой &НаСервере. В процедурах &НаСервереБезКонтекста метод РеквизитФормыВЗначение() недоступен.

Вариант 2: Использование метода Ссылка.ПолучитьОбъект()

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


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

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

  1. Все изменения, которые пользователь внес на форме, но еще не записал, не попадут в считываемый ДокументОбъект.
  2. Если документ еще не был записан в базу (новая ссылка не существует), вызов метода ПолучитьОбъект() вернет неопределенное значение или вызовет ошибку.
  3. Если после записи полученного объекта не обновить данные формы, интерфейс отобразит устаревшие сведения. Для обновления элементов формы при работе с объектом из базы данных используется метод ОбновитьОтображениеДанных().

Сравнение методов и рекомендации по применению

Для наглядности зафиксируем отличия двух подходов в виде таблицы возможностей:

  1. Источник данных: РеквизитФормыВЗначение() берет текущие несохраненные данные с экрана (из формы), а ПолучитьОбъект() считывает сохраненную версию из базы данных.
  2. Новые (незаписанные) объекты: РеквизитФормыВЗначение() успешно работает с новыми объектами, в то время как ПолучитьОбъект() требует наличия существующей ссылки в БД.
  3. Производительность: Сопряженная пара РеквизитФормыВЗначение() и ЗначениеВРеквизитФормы() выполняет полную сериализацию и десериализацию данных формы. На объектах с большими табличными частями (тысячи строк) это может вызывать задержки.

Оптимизация работы без полной конвертации объекта

Чтобы избежать нагрузки на сервер при постоянных сериализациях формы, рассмотрим альтернативные архитектурные решения:

  1. Вынос логики в Модуль Менеджера или Общий Модуль: Если алгоритм расчетный и не требует вызова методов самого объекта, выносите его в экспортную функцию общего модуля или модуля менеджера. Передавайте туда только необходимые данные (например, массив структур или значение конкретного реквизита), избегая полной сборки ДокументОбъект.
  2. Использование контекста без формы: В процедурах с директивой &НаСервереБезКонтекста для явного преобразования переданного реквизита используйте методы ДанныеФормыВЗначение() и ЗначениеВДанныеФормы().
  3. Штатное сохранение формы: Для выполнения записи из кода формы не следует вручную вызывать ДокументОбъект.Записать(). Рекомендуется использовать штатные методы формы ЭтаФорма.Записать() или ЗаписатьНаСервере(), которые корректно обрабатывают блокировки, транзакции и обновление интерфейса.
← На главную