Search code examples
c#nhibernateeventsfluent-nhibernateidentity

How do I get an entity's ID in an NHibernate listener before it's saved to the database?


We have a new requirement that every entity must have a user-assignable ID:

public class Entity
{
    public int ServerId { get; set; }
    public int UserId { get; set; }
}

The ServerId is an auto-generated ID using HiLo and the UserId is the user-specified ID. However, if the user does NOT set a UserId, it should default to whatever ServerId is. So I created a listener like this:

public class CustomEventListener : IPreInsertEventListener
{
    public bool OnPreInsert(PreInsertEvent @event)
    {
        var entity = @event.Entity as Entity;

        if (entity.UserId == 0)
        {
            entity.UserId = entity.ServerId;
        }

        return false;
    }
}

Unfortunately, at this pre-insert stage, the ServerId is always 0, so the UserId is always 0. Does anyone know how I can get the generated ServerId before it's saved to the database but after the ServerId is populated by NHibernate?

P.S. I'm also assuming that this is impossible with the Identity generator because it saves to the database and then gets the ID that the DB used. Can someone confirm this?


Solution

  • Found the solution thanks to Ayende's blog post here:

    http://ayende.com/Blog/archive/2009/04/29/nhibernate-ipreupdateeventlistener-amp-ipreinserteventlistener.aspx

    Turns out you have to not only change it in the entity, but also the entity state:

    public class CustomEventListener : IPreInsertEventListener
    {
        public bool OnPreInsert(PreInsertEvent @event)
        {
            var entity = @event.Entity as Entity;
    
            if (entity.UserId == 0)
            {
                entity.UserId = entity.ServerId;
                Set(@event.Persister, @event.State, "UserId", entity.UserId);
            }
    
            return false;
        }
    
        private void Set(IEntityPersister persister, object[] state, string propertyName, object value)
        {
            var index = Array.IndexOf(persister.PropertyNames, propertyName);
            if (index == -1)
                return;
            state[index] = value;
        }
    }