views:

1175

answers:

2

Hi,

I am using NHibernate interceptors to log information about Updates/Inserts/Deletes to my various entities.

Included in the information logged is the Entity Type and the Unique Id of the entity modified. The unique Id is marked as a <generator class="identity"> in the NHibernate mapping file.

The obvious problem is when logging an Insert operation using IInterceptor.OnSave() the Id of the entity has not yet been assigned.

How can I obtain the Id of the inserted entity before logging the audit information?

(I have looked into NHibernate Listeners PostSave event but can't get them working with the Spring.net configuration being used, so I would like to stick with interceptors if at all possible)

Many thanks.

Code:

    // object id parameter is null...
    public override bool OnSave(object entity, object id, object[] state, 
        string[] propertyNames, IType[] types)
    {            
        AddAuditItem(entity, INSERT);
        return false;            
    }
A: 

try the OnFlushDirty method.. or maybe PostFlush

edit: also, can you post your code? Don't you get the Id as a parameter to OnSave?

Matt Hinze
Thanks for the response.I have tried PostFlush but how can I tell which items in the ICollection entities parameter are the ones that have just been inserted? If there was a way of identifying this it would work OK...
TonE
I believe all of them.. is that not the case?
Matt Hinze
No, the collection contains all objects which have had their state updated from the database.
TonE
ok, i stand corrected. maybe this warrants a note to nhusers.
Matt Hinze
+3  A: 

I've worked around this problem by adding a list to my interceptor class which is populated with objects during the OnSave implementation.

In the PostFlush implementation the list is iterated over and each element is audited as an insert. The objects in this list have been persisted in PostFlush() and thus have generated IDs.

This seems to work OK but I'd be grateful if any potential pitfalls were pointed out :-)

public class AuditInterceptor : EmptyInterceptor
    {       
        // To hold inserted items to be audited after insert has been flushed
        private IList<object> insertItems = new List<object>();

       public override void PostFlush(System.Collections.ICollection entities)
        {            
            foreach (var entity in insertItems)
            {
                AddAuditItem(entity, INSERT);
            }
            insertItems.Clear();

            base.PostFlush(entities);
        }

        public override bool OnSave(object entity, object id, object[] state, 
            string[] propertyNames, IType[] types)
        {            
            var auditable = entity as IAuditable;
            if (auditable != null) insertItems.Add(entity);

            return false;            
        }
 }
TonE
+1 Wish I'd seen this twelve months ago!
MPritch