При изучении разработки в среде «1С:Предприятие 8» начинающие специалисты часто сталкиваются с непониманием того, почему при программном вызове метода Записать() система «игнорирует» обработчики событий формы. Кажется логичным: если мы инициируем запись, должны выполниться абсолютно все проверки и алгоритмы, которые мы тщательно прописали на форме. Однако на практике этого не происходит. Давайте подробно разберем, почему управляемая форма отсутствует при программном создании и изменении объектов, как разделяется логика интерфейса и базы данных, и в каких именно процедурах необходимо описывать бизнес-логику.
Для того чтобы понять логику платформы «1С:Предприятие», нам необходимо обратиться к фундаментальному архитектурному паттерну — MVC (Model-View-Controller или Модель-Представление-Контроллер). Платформа 1С строго разделяет сущности, отвечающие за хранение и обработку данных (бизнес-логику), от сущностей, которые эти данные визуализируют для пользователя.
Рассмотрим подробнее роли этих участников:
СправочникОбъект, ДокументОбъект или РегистрСведенийНаборЗаписей. Эти объекты «живут» исключительно на сервере. Их главная и единственная задача — обеспечить целостность данных, выполнить бизнес-проверки и записать информацию в таблицы СУБД. Они ничего «не знают» о том, как они выглядят на экране пользователя.УправляемаяФорма). Форма является визуальной оболочкой, «витриной» для данных. Её задача — предоставить пользователю удобный интерфейс для ввода, отобразить подсказки, раскрасить строки табличной части и передать команды пользователя на сервер.Проанализируем простую ситуацию. У одного справочника «Контрагенты» в конфигурации может быть создано несколько разных форм: «ФормаЭлемента», «ФормаЭлементаДляПродаж», «ФормаДляМобильногоКЛИЕНТА» и так далее. Если бы запись объекта жестко зависела от кода конкретной формы, то при программном создании контрагента система просто запуталась бы: код какой именно формы ей нужно выполнить?
Именно поэтому, когда вы пишете программный код создания и записи объекта, например, при загрузке данных из внешнего файла или веб-сервиса, форма не создается вовсе. Серверу не нужны «глаза» и визуальные элементы управления, он работает напрямую с объектом данных.
Рассмотрим пример типичного программного кода:
НовыйНоменклатура = Справочники.Номенклатура.СоздатьЭлемент();
НовыйНоменклатура.Наименование = "Процессор Intel Core i9";
НовыйНоменклатура.Записать();
В этом сценарии система выполняет запись напрямую в базу данных. Никакого клиентского контекста, окон, кнопок и, соответственно, событий управляемой формы в этот момент физически не существует в оперативной памяти сервера.
Для закрепления материала разберем по шагам и сравним последовательность событий, которые генерирует платформа 1С в двух различных ситуациях: когда пользователь нажимает кнопку «Записать» на форме и когда разработчик вызывает метод Записать() программно.
Когда пользователь работает в интерфейсе и инициирует запись, платформа запускает сложную сквозную цепочку событий, связывающую клиентское приложение, сервер формы и сервер базы данных:
Отказ = Истина.Теперь проанализируем, что происходит, когда разработчик в коде пишет Объект.Записать(). Цепочка событий колоссально сокращается, так как все интерфейсные этапы просто исключаются из работы:
Как мы видим, ни одно из событий управляемой формы (таких как ПередЗаписьюНаСервере, ПриЗаписиНаСервере, ПослеЗаписиНаСервере) при программной записи не вызывается и вызвано быть не может. В этом и заключается суть цитаты из книги «Разработка управляемого интерфейса».
Понимание этой разницы диктует строгие правила написания программного кода. Одной из самых частых ошибок среди новичков является некорректная работа с данными формы в процедуре ПередЗаписьюНаСервере.
Давайте выясним причину этой проблемы. В процедуру формы ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи) платформа передает специальный параметр — ТекущийОбъект. Этот параметр имеет тип прикладного объекта (например, ДокументОбъект.РеализацияТоваровУслуг), который система подготовила для отправки в базу данных.
Проанализируем некорректный пример кода, который часто пишут по ошибке:
&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
// ОШИБКА! Реквизит формы "Объект" в этот момент уже отделился от записываемого объекта.
// Изменения, внесенные сюда, будут проигнорированы и НЕ попадут в базу данных!
Объект.Комментарий = "Изменено через реквизит формы";
КонецПроцедуры
Если написать код таким образом, то значение комментария в базе данных не обновится, хотя визуально на форме в процессе интерактивной работы пользователь может увидеть изменения. Правильный и безопасный подход заключается в изменении свойств параметра ТекущийОбъект:
&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
// ПРАВИЛЬНО: Работаем непосредственно с записываемым прикладным объектом.
// Эти изменения будут гарантированно сохранены в СУБД.
ТекущийОбъект.Комментарий = "Изменено перед записью на сервере";
КонецПроцедуры
После успешной записи платформа автоматически синхронизирует сохраненный ТекущийОбъект обратно с экранным реквизитом формы Объект, и пользователь увидит актуальное значение на экране.
Важно понимать разницу в поведении системы с точки зрения транзакций баз данных для различных серверных процедур формы. Это знание убережет вас от блокировок таблиц и зависания системы при высокой нагрузке.
Разберем три ключевые точки серверных событий формы:
Отказ = Истина, транзакция в СУБД даже не начнется, и СУБД не будет заблокирована.Чтобы ваша конфигурация работала стабильно и предсказуемо как при интерактивной работе пользователя, так и при программной интеграции (например, обмене данными), придерживайтесь следующих правил распределения кода:
ПередЗаписью, ОбработкаПроведения, ОбработкаПроверкиЗаполнения). В этом случае правила контроля сработают одинаково надежно и при ручном вводе, и при автоматической загрузке данных.ПередЗаписью для нужных типов объектов. Этот код гарантированно выполнится при любом способе записи.