{"id":31,"date":"2013-08-24T23:04:00","date_gmt":"2013-08-24T23:04:00","guid":{"rendered":"http:\/\/tpodolak.com.hostingasp.pl\/blog\/2013\/08\/24\/nhibarnate-using-event-listeners-to-set-entity-modification-date\/"},"modified":"2016-01-30T23:46:34","modified_gmt":"2016-01-30T23:46:34","slug":"nhibarnate-using-event-listeners-to-set-entity-modification-date","status":"publish","type":"post","link":"https:\/\/tpodolak.com\/blog\/2013\/08\/24\/nhibarnate-using-event-listeners-to-set-entity-modification-date\/","title":{"rendered":"NHibarnate &#8211; using event listeners to set entity modification date"},"content":{"rendered":"<p>I think, that it is a common practice to store information about creation and modification date of entities. However keeping appropriate columns up to date manually is error prone. We must remember that every time we modify entity, we also have to change its modification date. Fortunately thanks to event listeners, NHibernate can do all of this boring stuff for us. Let&#8217;s start from creating class which implements two interfaces:<\/p>\n<ul>\n<li>IPreInsertEventListener<\/li>\n<li>IPreUpdateEventListener<\/li>\n<\/ul>\n<pre lang=\"csharp\">\r\npublic class NHListener : IPreInsertEventListener, IPreUpdateEventListener\r\n{\r\n    public bool OnPreInsert(PreInsertEvent @event)\r\n    {\r\n        throw new NotImplementedException();\r\n    }\r\n\r\n    public bool OnPreUpdate(PreUpdateEvent @event)\r\n    {\r\n        throw new NotImplementedException();\r\n    }\r\n}\r\n<\/pre>\n<p>As You probably guessed OnPreInsert method is invoked before insert, and OnPreUpdate is called before update of entity. Having prepared the basic skeleton of class, it is time to configure NHibernate to use our event listeners. The basic configuration is taken from my previous post about NHibernate <a href=\"http:\/\/tpodolak.com\/blog\/2013\/03\/25\/fluent-nhibernate-automappings\">automappings<\/a>, so I will only extend it by appending event listeners<\/p>\n<pre lang=\"csharp\">\r\nFluently.Configure().Database(\r\n                    MsSqlConfiguration.MsSql2008.ConnectionString(\r\n                        @\"YourConnectionString\"))\r\n                    .Mappings(val => val.AutoMappings.Add(CreateAutomappings))\r\n                    .ExposeConfiguration(val =>\r\n                    {\r\n                        val.AppendListeners(ListenerType.PreUpdate, new IPreUpdateEventListener[] { new NHListener() });\r\n                        val.AppendListeners(ListenerType.PreInsert, new IPreInsertEventListener[] { new NHListener() });\r\n                    })\r\n                    .BuildSessionFactory();\r\n<\/pre>\n<p>Now we can put some logic into OnPreInsert and OnPreUpdate functions. First of all we have to somehow identify entities which hold information about creation and modification time. In order to do that I created simple interface <i>IDateInfo<\/i><\/p>\n<pre lang=\"csharp\">\r\npublic interface IDateInfo\r\n{\r\n    DateTime ModificationDate { get; set; }\r\n    DateTime CreationDate { get; set; }\r\n}\r\n<\/pre>\n<p>In the next step we have to modify <i>OnPreInsert<\/i> and <i>OnPreUpdate<\/i> methods, so that they can set creation and modification date of entities which implement <i>IDateInfo<\/i> interface.<\/p>\n<pre lang=\"csharp\">\r\npublic class NHListener : IPreInsertEventListener, IPreUpdateEventListener\r\n{\r\n    public bool OnPreInsert(PreInsertEvent @event)\r\n    {\r\n        IDateInfo dateInfo;\r\n        if ((dateInfo = @event.Entity as IDateInfo) != null)\r\n        {\r\n            var currentDate = DateTime.Now;\r\n            dateInfo.CreationDate = dateInfo.ModificationDate = currentDate;\r\n        }\r\n        return false;\r\n    }\r\n\r\n    public bool OnPreUpdate(PreUpdateEvent @event)\r\n    {\r\n        IDateInfo dateInfo;\r\n        if ((dateInfo = @event.Entity as IDateInfo) != null)\r\n        {\r\n            var currentDate = DateTime.Now;\r\n            dateInfo.ModificationDate = currentDate;\r\n        }\r\n        return false;\r\n    }\r\n}\r\n<\/pre>\n<p>Unfortunately at this moment saving entity (which implements IDateInfo interface) will throw exception<br \/>\n<a href=\"http:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2013\/08\/nhibarnate-using-event-listeners-to-set-entity-modification-date\/Exception.png\" rel=\"attachment wp-att-342\"><img decoding=\"async\" src=\"http:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2013\/08\/nhibarnate-using-event-listeners-to-set-entity-modification-date\/Exception.png\" alt=\"Exception\" width=\"500\" class=\"aligncenter size-full wp-image-342\" srcset=\"https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2013\/08\/nhibarnate-using-event-listeners-to-set-entity-modification-date\/Exception.png 765w, https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2013\/08\/nhibarnate-using-event-listeners-to-set-entity-modification-date\/Exception-150x80.png 150w, https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2013\/08\/nhibarnate-using-event-listeners-to-set-entity-modification-date\/Exception-300x160.png 300w\" sizes=\"(max-width: 765px) 100vw, 765px\" \/><\/a><br \/>\nDespite the fact that we set values of <i>ModificationDate<\/i> and <i>CreationDate<\/i> properties , NHiberante seems not to notice that. That is why we have to manually update values of <i>State<\/i> object from <i>PreInsertEvent <\/i> and <i>PreUpdateEvent<\/i>. According to the documentation <i>State<\/i> object from class <i>PreInsertEvent<\/i> holds values which should be inserted and <i>State<\/i> object from class <i>PreUpdateEvent<\/i> holds values which should be updated. Function which update values of state object might look like that<\/p>\n<pre lang=\"csharp\">\r\nprivate void SetState(IEntityPersister persister, object[] state, string propertyName, object value)\r\n{\r\n    var index = Array.IndexOf(persister.PropertyNames, propertyName);\r\n    if (index == -1)\r\n        return;\r\n    state[index] = value;\r\n}\r\n<\/pre>\n<p>Updated NHListener class now looks like that<\/p>\n<pre lang=\"csharp\">\r\nusing System;\r\nusing System.Linq.Expressions;\r\nusing NHibernate.Event;\r\nusing NHibernate.Impl;\r\nusing NHibernate.Persister.Entity;\r\n\r\nnamespace DataAccessLayer\r\n{\r\n    public class NHListener : IPreInsertEventListener, IPreUpdateEventListener\r\n    {\r\n        private static readonly string ModificationDatePropertyName = GetPropertyName<IDateInfo>(val => val.ModificationDate),\r\n                                       CreationDatePropertyName = GetPropertyName<IDateInfo>(val => val.CreationDate);\r\n\r\n        public bool OnPreInsert(PreInsertEvent @event)\r\n        {\r\n            IDateInfo dateInfo;\r\n            if ((dateInfo = @event.Entity as IDateInfo) != null)\r\n            {\r\n                var currentDate = DateTime.Now;\r\n                dateInfo.CreationDate = dateInfo.ModificationDate = currentDate;\r\n                SetState(@event.Persister, @event.State, ModificationDatePropertyName, currentDate);\r\n                SetState(@event.Persister, @event.State, CreationDatePropertyName , currentDate);\r\n            }\r\n    \r\n            return false;\r\n        }\r\n    \r\n        public bool OnPreUpdate(PreUpdateEvent @event)\r\n        {\r\n            IDateInfo dateInfo;\r\n            if ((dateInfo = @event.Entity as IDateInfo) != null)\r\n            {\r\n                var currentDate = DateTime.Now;\r\n                dateInfo.ModificationDate = currentDate;\r\n                SetState(@event.Persister, @event.State, ModificationDatePropertyName, currentDate);\r\n            }\r\n            return false;\r\n        }\r\n        \r\n        private void SetState(IEntityPersister persister, object[] state, string propertyName, object value)\r\n        {\r\n            var index = Array.IndexOf(persister.PropertyNames, propertyName);\r\n            if (index == -1)\r\n                return;\r\n            state[index] = value;\r\n        }\r\n    \r\n        private static string GetPropertyName<TType>(Expression<Func<TType, object>> expression)\r\n        {\r\n            return ExpressionProcessor.FindPropertyExpression(expression.Body);\r\n        }\r\n    }\r\n}\r\n<\/pre>\n<p>As You can see, after setting values of IDateInfo I also call function <i>SetState<\/i> and update state of appropriate properties. From now everything works fine and our entities can be saved without problems. Source code for this post can be found <a href=\"https:\/\/github.com\/tpodolak\/Blog\/tree\/master\/NHibernateEventListener\">here<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>I think, that it is a common practice to store information about creation and modification date of entities. However keeping appropriate columns up to date manually is error prone. We must remember that every time we modify entity, we also have to change its modification date. Fortunately thanks to event listeners, NHibernate can do all [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3,65,66,46],"tags":[159,208,209,193],"class_list":["post-31","post","type-post","status-publish","format-standard","hentry","category-c","category-eventlisteners","category-fluentnhibernate","category-nhibernate","tag-c","tag-eventlisteners","tag-fluentnhibernate","tag-nhibernate"],"_links":{"self":[{"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/posts\/31","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/comments?post=31"}],"version-history":[{"count":4,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/posts\/31\/revisions"}],"predecessor-version":[{"id":343,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/posts\/31\/revisions\/343"}],"wp:attachment":[{"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/media?parent=31"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/categories?post=31"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/tags?post=31"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}