Как передать и сохранить данные между вызовами событий ПередЗаписью и ПриЗаписи в 1С

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке бизнес-логики в 1С регулярно возникает задача сравнения состояний объекта до и после его сохранения в базу данных. Типичный сценарий: в обработчике события ПередЗаписью необходимо зафиксировать старое или текущее значение реквизита, а в событии ПриЗаписи — проверить, изменилось ли оно, и при необходимости выполнить дополнительные действия (например, отправить уведомление, записать лог или вызвать сторонний сервис).

Рассмотрим подробнее, какими механизмами платформы 1С:Предприятие следует пользоваться для решения этой задачи, какие нюансы нужно учитывать при работе с общими модулями и подписками на события, а также как правильно передавать данные между клиентом и сервером.

Основной инструмент: свойство ДополнительныеСвойства

Когда обработка выполняется в рамках одного серверного вызова (транзакции записи), наиболее правильным и универсальным решением является использование свойства ДополнительныеСвойства объекта БД.

Свойство ДополнительныеСвойства представляет собой встроенный объект типа Структура, который автоматически присутствует у всех прикладных объектов платформы (справочники, документы, наборы записей регистров, планы видов характеристик и др.). Главное преимущество этого свойства заключается в том, что оно «живет» вместе со ссылкой на объект в оперативной памяти на протяжении всего серверного вызова.

Это делает ДополнительныеСвойства идеальным контейнером для передачи произвольных пользовательских данных между различными процедурами-обработчиками:

  1. Обработчики событий в модуле самого объекта (ПередЗаписью, ПриЗаписи, ОбработкаПроведения).
  2. Обработчики в подписках на события, расположенные в общих модулях.

В отличие от переменных модуля (объявленных через директиву Перем), которые недоступны в контексте экспортных процедур общих модулей и подписок на события, ДополнительныеСвойства передаются вместе с параметром Источник в любую подписку.

Как проверить изменение реквизита в событии ПередЗаписью

Разберем по шагам, как зафиксировать факт изменения реквизита объекта в момент перед его записью в базу данных.

В событии ПередЗаписью объект (обозначаемый как ЭтотОбъект в модуле объекта или Источник в подписке на событие) содержит **новые** данные, которые пользователь или алгоритм пытается записать. Старые данные, записанные в базе на данный момент, можно получить путем обращения к базе данных через считывание реквизита по ссылке Источник.Ссылка.ИмяРеквизита (если объект не является новым).

Проанализируем пример кода для подписки на событие ПередЗаписью:


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

КонецПроцедуры

Безопасное чтение данных в событии ПриЗаписи

После того как транзакция записи успешно продвинулась к этапу ПриЗаписи, данные в базе уже обновлены. Нам необходимо безопасно прочитать сохраненную информацию из ДополнительныеСвойства.

Для предотвращения ошибок обращения к несуществующим ключам структуры настоятельно рекомендуется использовать метод Свойство(). Посмотрим, как выглядит обработка в событии ПриЗаписи:


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

КонецПроцедуры

Важные технические нюансы работы с ДополнительныеСвойства

При работе со структурой ДополнительныеСвойства следует учитывать ряд особенных ситуаций:

  1. Повторная запись объекта в рамках одного серверного вызова: Если в процессе выполнения одного кода один и тот же объект программно записывается несколько раз подряд (метод Записать() вызывается повторно без перечитывания объекта из БД), данные в ДополнительныеСвойства **не очищаются автоматически**. Чтобы избежать повторного срабатывания логики при второй записи, удаляйте обработанные ключи с помощью метода ДополнительныеСвойства.Удалить("ИмяКлюча").
  2. Поведение при откате транзакции: События ПередЗаписью и ПриЗаписи выполняются внутри одной транзакции базы данных. Если в процессе выполнения ПриЗаписи возникнет исключение или переменная Отказ установится в Истина, транзакция записи в БД будет отменена. Однако сам объект 1С в оперативной памяти сервера (включая заполненную структуру ДополнительныеСвойства) останется в текущем состоянии. Это важно учитывать при повторных попытках обработки того же объекта.

Передача данных из управляемой формы на сервер при интерактивной записи

Выясним, как поступить, если данные для записи подготавливаются пользователем на клиенте в управляемой форме, и их нужно пробросить через клиентские события в модуль объекта или подписку.

Рассмотрим цепочку передачи контекста по шагам:

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

Передача данных между различными серверными вызовами

Если цепочка действий пользователя или системы не помещается в один серверный вызов (например, между определением изменений и финальной записью происходит диалог с пользователем или серия клиент-серверных вызовов), свойство ДополнительныеСвойства использовать нельзя, так как экземпляр объекта в памяти между вызовами уничтожается.

В таких ситуациях применяются альтернативные механизмы платформы:

  1. Временное хранилище (ПоместитьВоВременноеХранилище / ПолучитьИзВременногоХранилища): Позволяет сохранить произвольную структуру данных по адресу (UUID формы) и прочитать ее при следующем вызове.
  2. Реквизиты формы: Используются для сохранения состояния между клиентскими событиями в рамках работы одной открытой формы.
  3. Параметры сеанса (ПараметрыСеанса): Подходят для глобального хранения небольших данных в рамках текущего сеанса пользователя.
  4. Регистры сведений: Применяются, если данные нужно гарантированно сохранить между разными сеансами пользователей, фоновыми заданиями или независимыми транзакциями.

Таким образом, для хранения и передачи значений между вызовами событий одного объекта в 1С наиболее эффективным и стандартным инструментом является использование ДополнительныеСвойства. Это обеспечивает чистый, отказоустойчивый и универсальный код как в модулях объектов, так и в общих модулях подписок на события.

← На главную