Saving a new object in the PreInsert / PreDelete event listener is not saved in the database

I configured the PreInsert and PreDelete event listener in NHibernate 2.1. For insertion and deletion in a specific table, I want to write the audit event to a separate audit table.

public class AuditEventListener : IPreInsertEventListener, IPreDeleteEventListener { private static readonly ILog Log = LogManager.GetLogger(typeof(AuditEventListener)); public bool OnPreInsert(PreInsertEvent @event) { if (!(@event.Entity is IAuditable)) return false; return AuditEvent(@event.Session.GetSession(EntityMode.Poco), true, (@event.Entity as IAuditable)); } public bool OnPreDelete(PreDeleteEvent @event) { if (!(@event.Entity is IAuditable)) return false; return AuditEvent(@event.Session.GetSession(EntityMode.Poco), false, (@event.Entity as IAuditable)); } private bool AuditEvent(ISession session, bool isInsert, IAuditable entity) { if (entity is ArticleBinding) { if (Log.IsDebugEnabled) Log.DebugFormat(" audit event ({0}), entity is ArticleBinding", ((isInsert) ? "Insert" : "Delete")); AddArticleBindingAuditEvent(session, isInsert, (entity as ArticleTagBinding)); } return false; } private void AddArticleBindingAuditEvent(ISession session, bool isInsert, ArticleBinding binding) { var auditRecord = new AuditArticleBinding() { ArticleId = binding.ArticleId, Action = (isInsert) ? "Add" : "Delete", LoggedBy = string.IsNullOrEmpty(Thread.CurrentPrincipal.Identity.Name) ? "Unknown" : Thread.CurrentPrincipal.Identity.Name }; session.Save(auditRecord); } } 

I worked on the issue of using the same session that threw the exception. Now all the code is working fine and my log statements get caught, but the audit record is never inserted. Using NHProf, I see that an INSERT call never occurs.

Why would this code not call INSERT?

+6
source share
2 answers

I am currently working on the same thing and have been facing the same problem. An attempt to save a new object and an INSERT is not even performed. I found an article about using Pre [Update | Insert] Listeners for audit on the record , where one comment asks about the insertion of a new object, and the author replies that a child session is required.

 private void AddArticleBindingAuditEvent(ISession session, bool isInsert, ArticleBinding binding) { var childSession = e.Session.GetSession(EntityMode.Poco); var auditRecord = new AuditArticleBinding() { ArticleId = binding.ArticleId, Action = (isInsert) ? "Add" : "Delete", LoggedBy = string.IsNullOrEmpty(Thread.CurrentPrincipal.Identity.Name) ? "Unknown" : Thread.CurrentPrincipal.Identity.Name }; childSession.Save(auditRecord); childSession.Flush(); } 

Another link for you (which I found today): Audit using NHibernate listeners . It gives a complete example of inserting a new audit log, but uses Post listeners and is not related to the entity (almost the same as me, using persister to search for changed values). I'm not sure what the advantage of this is using Pre listeners.

And like β€œanyway”, you need to make sure you hook up the event listener before your configuration:

 var eventListener = new AuditEventListener(); config.SetListener(ListenerType.PreInsert, eventListener); config.SetListener(ListenerType.PreDelete, eventListener); 

Full disclosure . I am new to NHibernate, so if there is something that I missed or could do better, please let me know. The above method works for me in that my record is successfully inserted into the database, but in some cases it does not work. Although I'm pretty sure this is specific to my application (from which I am new to the codebase, so I'm still working)

+3
source

After spending a full day trying to figure out the cause of the problem without success, I hope I found this thread that explains:

Looking at the Hibernate code, it seems that the insertion is only using the state attribute PreInsertEvent. So while you are updating event.getEntity (), I don't think its getting inserted during the insert phase.

The solution consists of 1) updating the object to pass the check (for example, @NotNull) and 2) updating the state to save the new values ​​in the database!

In my application, this causes ugly code, for example:

 @Override public boolean onPreInsert(PreInsertEvent event) { Object entity = event.getEntity(); // Assumption: entity cannot be null if (entity instanceof AbstractBase) { String[] names = event.getPersister().getPropertyNames(); for (int i = 0; i < names.length; ++i) { if ("insertWhen".equals(names[i])) { ((AbstractBase<?>) entity).setInsertWhen(new Date()); event.getState()[i] = ((AbstractBase<?>) entity).getInsertWhen(); } else if (...) { ... } } } 

I am very surprised to see that this issue, documented 6 years ago, is still a problem for many of us.

Hope this helps.

0
source

Source: https://habr.com/ru/post/885758/


All Articles