Обработчики событий NHibernate при подтверждении транзакции

В этом примере рассмотрен сценарий обработки событий после их выполнения. В данной статье описаны два обработчика событий:

  1. При создании документа. Заполняется атрибут Описание документа автором создания.
  2. При изменении документа. Заполняется атрибут Изменил документ автором изменения.
  3. При изменении объекта с коллекцией телефонов. Если в коллекции телефонов объекта (контрагенты, контакты, возможности) используется телефон с недопустимыми символами, недопустимые символы удаляются из номера телефона.

При создании документа в поле Описание будет записан автор и дата создания документа, а при изменении будет записан автор изменения и дата изменения документа в поле Изменил документ.

События вызываются при подтверждении транзакции в ELMA (UnitOfWork). Например, транзакция подтверждается один раз после выполнения блока сценария или при нажатии на кнопку выполнения задачи. Перед событием при подтверждении транзакции вызывается Session.Flush и данные уже отправлены в БД, и узнать предыдущие значения данных в некоторых случаях сложно, также невозможно отменить событие (в отличие от Pre событий в EntityEventListener). Внутри событий PostFlush можно пользоваться обычными менеджерами и изменять объекты, тогда как в EntityEventListener сделать просто так не получится. Стоит отметить, что события PostFlushEventListener происходят позже, нежели события EntityEventListener.

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

Рис. 1. Заполненные поля «Описание» и «Изменил документ» после создания и изменения документа

Рис. 2. Удаление недопустимых символов при сохранении контакта с коллекцией телефонов

Методы базового класса PostFlushEventListener

Базовый класс PostFlushEventListener имеет следующие методы:

/// <summary>
/// После вставки
/// </summary>
/// <param name="event">Параметры события</param>
public virtual void OnPostInsert(PostInsertEvent @event)

/// <summary>
/// После обновления
/// </summary>
/// <param name="event">Параметры события</param>
public virtual void OnPostUpdate(PostUpdateEvent @event)

/// <summary>
/// После удаления
/// </summary>
/// <param name="event">Параметры события</param>
public virtual void OnPostDelete(PostDeleteEvent @event)

/// <summary>
/// После обновления элемента в коллекции
/// </summary>
/// <param name="event">Параметры события</param>
public virtual void OnPostUpdateCollection(PostCollectionUpdateEvent @event)

Пример класса точки расширения

[Component]
class PostFlush : PostFlushEventListener
{
    // событие создание объекта/документа
    public override void OnPostInsert(PostInsertEvent @event)
    {
        //    Определяем тип документа
        var fax = @event.Entity as IDocFax;
        if (fax != null)    //   интерфейс  документа  типа  Факс 
        {
            // заполняем атрибут Описание документа
            fax.Description = string.Format("Автор создания: {0}\r\n", fax.CreationAuthor.FullName);
        }
    }

    public override void OnPostUpdate(PostUpdateEvent @event)
    {
        //    Определяем  тип документа
        var fax = @event.Entity as IDocFax;
        if (fax != null)    //   интерфейс  документа  типа  Факс
        {
            fax.IzmenilDokument = string.Format("{0} в {1}", fax.ChangeAuthor, DateTime.Now.ToString(CultureInfo.InvariantCulture));
        }
    }

    public override void OnPostUpdateCollection(PostCollectionUpdateEvent @event)
    {
        var collection = @event.Collection;
        var collectionEntry = @event.Session.PersistenceContext.GetCollectionEntry(@event.Collection);
        var collectionEntries = collection.Entries(collectionEntry.LoadedPersister);

        var listChars = new List<string> { " ", "-", "(", ")" }; //Список символов, которые хотим заменять
        foreach (var entry in collectionEntries)
        {
            if (!(entry is IPhone)) continue; //Если объект коллекции телефон - продолжаем
            var phone = entry as IPhone;
            var lastNumber = phone.PhoneString;
            foreach (var str in listChars)
            {
                lastNumber = lastNumber.Replace(str, string.Empty); //Заменяем символы из }
            phone.PhoneString = lastNumber; //Пересохраняем телефон с замененными символами
        }
    }
}

Ссылки на элементы API

Прикрепленные файлы