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