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