3

I am creating an ASP.NET MVC3 application using NHIBERNATE. I have a base class Entity that is used to capture some audit information like CreatedBy, CreatedOn, UpdatedBy, UpdatedOn, etc. These properties should get populated automagically whenever a derived class is created and persisted/updated.

As the Entity type and all other types are defined in the DOMAIN Assembly, What would be the best way to percolate USER information from Web project to DOMAIN to populate the information in Entity base class

EDIT

Further,

  1. Currently, i define all properties as public virtual, so how do I implement them so that the dates/userId are created on the fly at the time of persistence.
  2. I want Base class properties to persist in each table for derived concrete classes (table per concrete class). How do i specify it using FLUENT NHIBERNATE (I am not using Automapping)
Seany84
  • 5,526
  • 5
  • 42
  • 67
EagerToLearn
  • 827
  • 2
  • 14
  • 24
  • Hey all geniuses out there, please help. I am sure it's a very usual scenario for usually all applications. – EagerToLearn Mar 29 '12 at 17:51
  • There are lots of examples on Google: "nhibernate audit interceptor". There are simpler examples than Martin's below. You can also use event listeners. Couple of things to be aware of: 1) you have to update the state collection of the entity because that is what is persisted. See 'state[i]' in Martin's sample; 2) if you have set NHibernate to use dynamic sql there is a bug that stops it seeing your changes. See http://stackoverflow.com/questions/4383420/nhibernate-preupdate-event-listener-not-persisting-changes – Rob Kent Mar 30 '12 at 08:21

1 Answers1

2

Use an Interceptor when you open the session:

sessionFactory.OpenSession(new AuditInterceptor());

File: AuditInterceptor.cs

using System;
using NHibernate;
using NHibernate.Type;
using System.Threading;
using System.Security;

namespace bla
{
    /// <summary>
    /// NHibernate Interceptor that stores audit information (idlogin and datetime.now) on every save and update
    /// </summary>
    public class AuditInterceptor : EmptyInterceptor
    {

        private int updates;
        private int creates;
        private int loads;
        private ISession session;

        public override void OnDelete(object entity,
                                      object id,
                                      object[] state,
                                      string[] propertyNames,
                                      IType[] types)
        {
            // do nothing
        }

        public override bool OnFlushDirty(object obj, object id, object[] currentState, object[] previousState, string[] propertyNames, IType[] types)
        {
            bool found = false;
            if (obj is Entity)
            {
                updates++;
                for (int i = 0; i < propertyNames.Length; i++)
                {
                    if ("dtlastchanged".Equals(propertyNames[i].ToLower()))
                    {
                        currentState[i] = DateTime.Now;
                        found = true;
                    }
                    if ("lastchangedby".Equals(propertyNames[i].ToLower()))
                    {
                        currentState[i] = this.session.Get<Login>(IdLogin, LockMode.None);
                        found = true;
                    }
                }
            }
            return found;
        }

        public override bool OnLoad(object obj, object id, object[] state, string[] propertyNames, IType[] types)
        {
            if (obj is Entity)
            {
                loads++;
            }
            return false;
        }

        public override bool OnSave(object entity,
                                    object id,
        object[] state,
        string[] propertyNames,
        IType[] types)
        {
            bool found = false;
            if (entity is Entity)
            {
                creates++;
                for (int i = 0; i < propertyNames.Length; i++)
                {
                    if ("dtlastchanged".Equals(propertyNames[i].ToLower()))
                    {
                        state[i] = DateTime.Now;
                        found = true;
                    }
                    if ("lastchangedby".Equals(propertyNames[i].ToLower()) && !(entity is Login && (entity as Login).IsInVerification))
                    {
                        state[i] = this.session.Get<Login>(IdLogin, LockMode.None);
                        found = true;
                    }
                }
            }
            return found;
        }

        public override void AfterTransactionCompletion(ITransaction tx)
        {
            //if (tx.WasCommitted)
            //{
            //    System.Console.WriteLine("Creations: " + creates + ", Updates: " + updates, "Loads: " + loads);
            //}
            updates = 0;
            creates = 0;
            loads = 0;
        }

        public override void SetSession(ISession session)
        {
            this.session = session;
            base.SetSession(session);
        }

        protected long IdLogin
        {
            get
            {
                return (Thread.CurrentPrincipal.Identity as CustomIdentity).IdLogin; // or something else that holds the id of the current logged in user
            }
        }
    }
}
Martin
  • 1,149
  • 7
  • 13