[ELMA3] Обработчики событий NHibernate
В этом примере рассмотрен сценарий обработки событий:
- OnPreUpdate (проверка на наличие заполненного поля Годовой оборот в объекте Контрагент).
- OnPostUpdate (запись в активность по контрагенту изменение имени контрагента).
- OnPreUpdateCollection (запись в активность по контрагенту добавленные/удаленные телефоны).
- OnPostUpdateCollection (проверка на использование в поле и»символов, отличных от цифр, если такие символы есть, сохранить контрагент не удастся, о чем пользователь будет предупрежден).
Суть Pre событий в том, что при выполнении действий с объектом (добавление/изменение) существует возможность отменить само событие. События Pre можно применить для проверки введенных данных в поля объекта, если данные введены неверно или произошла ошибка, событие можно отменить.
PreUpdateCollection – это единственное событие, где можно получить и сравнить значение коллекции 1-N.
События Post выполняются после обмена данными с БД. Данное событие можно применить для записи истории по объекту, логирования, пересчета данных.
В данном примере будет продемонстрировано, как получить старое/новое значение коллекции, а также как получить старое/новое значение поля объекта.
Все события EntityEventsListener выполняются в момент вызова Save у объекта, следовательно, событие будет выполняться даже в том случае, если в сценариях будет создаваться/изменяться объект при вызове Save. Использование именно EntityEventsListener бывает необходимо, если после изменения объекта в сценариях и его сохранения при помощи Save необходимо выполнение дополнительного кода после сохранения объекта, который указан в EntityEventsListener.
Пример отображения данных
Рис. 1. Ведение истории по полям контрагента и история по коллекции объектов внутри контрагента (Телефон)
Рис. 2. Проверка на использование недопустимых символов в поле «Телефоны»
Методы базового класса EntityEventsListener
Базовый класс EntityEventsListener имеет следующие методы:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | /// <summary> /// Перед вставкой /// </summary> /// <param name="event">Параметры события</param> /// <returns><c>true</c>, если нужно первать операцию</returns> public virtual bool OnPreInsert(PreInsertEvent @ event ) /// <summary> /// После вставки /// </summary> /// <param name="event">Параметры события</param> public virtual void OnPostInsert(PostInsertEvent @ event ) /// <summary> /// Перед обновлением /// </summary> /// <param name="event">Параметры события</param> /// <returns><c>true</c>, если нужно первать операцию</returns> public virtual bool OnPreUpdate(PreUpdateEvent @ event ) /// <summary> /// После обновления /// </summary> /// <param name="event">Параметры события</param> public virtual void OnPostUpdate(PostUpdateEvent @ event ) /// <summary> /// Перед удалением /// </summary> /// <param name="event">Параметры события</param> /// <returns><c>true</c>, если нужно первать операцию</returns> public virtual bool OnPreDelete(PreDeleteEvent @ event ) /// <summary> /// После удаления /// </summary> /// <param name="event">Параметры события</param> public virtual void OnPostDelete(PostDeleteEvent @ event ) /// <summary> /// После удаления элемента в коллекции /// </summary> /// <param name="event">Параметры события</param> public virtual void OnPostRemoveCollection(PostCollectionRemoveEvent @ event ) /// <summary> /// После пересоздания элемента в коллекции /// </summary> /// <param name="event">Параметры события</param> public virtual void OnPostRecreateCollection(PostCollectionRecreateEvent @ event ) /// <summary> /// После обновления элемента в коллекции /// </summary> /// <param name="event">Параметры события</param> public virtual void OnPostUpdateCollection(PostCollectionUpdateEvent @ event ) /// <summary> /// Перед удаления элемента в коллекции /// </summary> /// <param name="event">Параметры события</param> public virtual void OnPreRemoveCollection(PreCollectionRemoveEvent @ event ) /// <summary> /// Перед пересозданием элемента в коллекции /// </summary> /// <param name="event">Параметры события</param> public virtual void OnPreRecreateCollection(PreCollectionRecreateEvent @ event ) /// <summary> /// Перед обновлением элемента в коллекции /// </summary> /// <param name="event">Параметры события</param> public virtual void OnPreUpdateCollection(PreCollectionUpdateEvent @ event ) /// <summary> /// Перед загрузкой /// </summary> /// <param name="event"></param> public virtual void OnPreLoad(PreLoadEvent @ event ) |
Пример класса точки расширения
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | [Component] public class EntityEvent : EntityEventsListener { public override void OnPostUpdateCollection(PostCollectionUpdateEvent @ event ) { var contr = @ event .AffectedOwnerOrNull as IContractor; if (contr != null ) { var collection = @ event .Collection; var collectionEntry = @ event .Session.PersistenceContext.GetCollectionEntry(@ event .Collection); var collectionEntries = collection.Entries(collectionEntry.LoadedPersister); var listChars = new List< string > { " " , "-" , "(" , ")" }; var index = 1; foreach (var entry in collectionEntries) { if (!(entry is IPhone)) continue ; var phone = entry as IPhone; long number; var lastNumber = phone.PhoneString; foreach (var str in listChars) { if (lastNumber != null ) lastNumber = lastNumber.Replace(str, string .Empty); } if (! long .TryParse(lastNumber, out number)) throw new Exception( string .Format( "Телефон №{0} имеет недопустимые символы" , index)); index++; } } } //Запись истории изменения имени контрагента public override void OnPostUpdate(PostUpdateEvent @ event ) { if (!(@ event .Entity is IContractor)) return ; var nameIndex = Array.IndexOf(@ event .Persister.PropertyNames, "Name" ); var contractor = @ event .Entity as IContractor; if (( string )@ event .OldState[nameIndex] != ( string )@ event .State[nameIndex]) { var comment = InterfaceActivator.Create<IComment>(); comment.CreationAuthor = UserManager.Instance.Load(SecurityConstants.SystemUserUid); comment.CreationDate = DateTime.Now; comment.Text += string .Format( "{2} изменил имя контрагента с {0} на {1}\r\n" , @ event .OldState[nameIndex], @ event .State[nameIndex], contractor.ChangeAuthor.FullName); comment.Save(); contractor.Comments.Add(comment); var actionHandler = Locator.GetServiceNotNull<IEntityActionHandler>(); actionHandler.ActionExecuted(EntityActionEventArgs.TryCreate( null , contractor, ContractorActions.AddComment)); } } //Проверка корректности введенного номера телефона на наличие посторонних символов/букв public override void OnPreUpdateCollection(PreCollectionUpdateEvent @ event ) { var contr = @ event .AffectedOwnerOrNull as IContractor; if (contr != null ) { var collectionEntry = @ event .Session.PersistenceContext.GetCollectionEntry(@ event .Collection); var newCollection = (@ event .Collection as IEnumerable).Cast< object >().ToList(); //Новая коллекция var oldCollection = (collectionEntry.Snapshot as IEnumerable).Cast< object >().ToList(); //Старая коллекция var removed = oldCollection.Where(item => !newCollection.Contains(item)).ToArray(); //Удаленные элементы в новой коллекции var added = newCollection.Where(item => !oldCollection.Contains(item)).ToArray(); //Добавленные элементы в новой коллекции if (collectionEntry.Role.EndsWith( ".Phone" )) { var comment = InterfaceActivator.Create<IComment>(); comment.CreationAuthor = UserManager.Instance.Load(SecurityConstants.SystemUserUid); comment.CreationDate = DateTime.Now; foreach (var add in added) { var phone = add as IPhone; if (phone != null ) { comment.Text += string .Format( "Добавлен новый телефон {0}\r\n" , phone.PhoneString); } } foreach (var rem in removed) { var phone = rem as IPhone; if (phone != null ) { comment.Text += string .Format( "Телефон {0} был удален\r\n" , phone.PhoneString); } } comment.Save(); contr.Comments.Add(comment); var actionHandler = Locator.GetServiceNotNull<IEntityActionHandler>(); actionHandler.ActionExecuted(EntityActionEventArgs.TryCreate( null , contr, ContractorActions.AddComment)); } } } //Проверка на заполненность поля "Годовой доход", если поле не заполнено - событие прерывается public override bool OnPreUpdate(PreUpdateEvent @ event ) { if (@ event .Entity is IContractor) { try { const double zero = 0; var nameIndex = Array.IndexOf(@ event .Persister.PropertyNames, "AnnualIncome" ); var annualIncomeValue = @ event .State[nameIndex]; if (annualIncomeValue != null && !annualIncomeValue.ToString().IsNullOrWhiteSpace() && ( double )annualIncomeValue != zero && ( double )annualIncomeValue > zero) { Logger.Log.Error( "Значение поля годовой доход заполнено корректно" ); //Обработка события return false ; } Logger.Log.Error( "Значение поля годовой доход меньше нуля, ноль или null" ); return true ; //Прервать событие } catch (Exception ex) { Logger.Log.Error(ex.Message); return true ; //Прервать событие } } return false ; } } |