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