3

I recently have found out how to audit instances with the IPreDeleteEventListener, IPreInsertEventListener and IPreUpdateEventListener in the NHibernate.Event namespace.

However, it still confuses me what shall these event return either on successful or unsuccessful finality.

For example, let's take a look at Ayende's blog article found here:

Following his example, one could implement the interfaces as following:

public class AuditEventListener : IPreInsertEventListener {
    public bool OnPreInsert(OnPreInsert @event) {
        var audit = @event.Entity as IHaveAuditInformation;
        if (audit == null) return false;

        var time = DateTime.Now;
        var name = WindowsIdentity.GetCurrent().Name;

        Set(@event.Persister, @event.State, "CreatedAt", time);
        Set(@event.Persister, @event.State, "CreatedBy", name);

        audit.CreatedAt = time;
        audit.CreatedBy = name;

        return false;
    }
}

What odes it actually mean to return either true or false as return value, since I have another example where true is returned instead of false as Ayende wrote.

Which seems to return true instead of false.

public class SoftDeletableListener : IPreDeleteEventListener {
    public void Register(Configuration cfg) {
        cfg.EventListeners.PreDeleteEventListeners = 
            new IPreDeleteEventListener[] { this }
                .Concat(cfg.EventListeners.PreDeleteEventListeners)
                .ToArray();
    }

    public Boolean OnPreDelete(PreDeleteEvent @event) {
        ISoftDeletable softDeletable = @event.Entity as ISoftDeletable;

        if (softDeletable == null) return true;

        EntityEntry entry = @event.Session
            .GetSessionImplementation()
            .PersistenceContext
            .GetEntry(@event.Entity);
        entry.Status = Status.Loaded;

        softDeletable.Deleted = true;

        Object id = @event.Persister
            .GetIdentifier(@event.Entity, @event.Session.EntityMode);
        Object [] fields = @event.Persister
            .GetPropertyValues(@event.Entity, @event.Session.EntityMode);
        Object version = @event.Persister
            .GetVersion(@event.Entity, @event.Session.EntityMode);

        @event.Persister.Update(id
            , fields
            , new Int32[1]
            , false
            , fields
            , version
            , @event.Entity
            , null
            , @event.Session.GetSessionImplementation());

        return true;
    }
}

So I wonder, what false/true actually tells NHibernate depending on the listener dealt with.

Miquel
  • 15,405
  • 8
  • 54
  • 87
Will Marcouiller
  • 23,773
  • 22
  • 96
  • 162
  • In the `SoftDeletableListener` example, shouldn't be `if (softDeletable == null) return false;` (`false` instead of `true`)? Otherwise no entity will be deleted, whether it's `ISoftDeletable` or not. – lalibi Jul 06 '16 at 15:38

1 Answers1

4

The returned value in this case should be enum, Let's use the name OnPreEventResult, and these would be the possible values:

  • OnPreEventResult.Continue => to continue currently return false
  • OnPreEventResult.Break => at the moment, when the true is returned the Action is aborted

So, as both examples above show, we can use the return value to manage the execution flow:

  1. to Continue:
    If we in the AuditEventListener return false, we in fact return something like OnPreEventResult.Continue. We've made some custome logic, and we want NHibernate to continue... so the false is returned

  2. to Break/Abort:
    Ayende's example is showing us how to change the real DELETE into UPDATE. Update is called explicitly @event.Persister.Update(... and the delete is not executed due to the returned value true, i.e. OnPreEventResult.Break

In the code, the returned values are stored in local variable called veto, which is again more self descriptive.

See:

A snippet from the EntityInsertAction, the Execute() method:

...
bool veto = PreInsert();

if (!veto)
{    
    persister.Insert(id, state, instance, Session);
...
Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
  • +1 Thanks for this great explanation! I now better understand what is going on. These examples, IMHO, would have been much more cleaner code if they would have actually used this `OnPreventResult` enum. Thanks @Radim! – Will Marcouiller Feb 18 '14 at 14:41
  • Great if that helped anyhow. Enjoy NHibernate :) – Radim Köhler Feb 18 '14 at 15:19
  • Great explanation. In reality the example is wrong. If the class does not implement "Soft Delete" contract, the interceptor should return false and not true. – Raffaeu Dec 06 '17 at 10:21