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