Custom NHibernate User Type

How to use a custom NHibernate User Type

 

To store the state of a Risk (ie RiskState) as a value in a column we can use a NHibernate.UserType

 

The RiskState can be one of the following: (these are all derived from RiskState which implements IRiskState)

image

Our user type
 public class RiskStateNameUserType : IUserType
    {
        #region IUserType Members

        public object Assemble(object cached, object owner)
        {
            return cached;
        }

        public object DeepCopy(object value)
        {
            return value;
        }

        public object Disassemble(object value)
        {
            return value;
        }

        public int GetHashCode(object x)
        {
            return x.GetHashCode();
        }

        public bool IsMutable
        {
            get { return false; }
        }

        public object NullSafeGet(System.Data.IDataReader dr, string[] names, object owner)
        {
            var property0 = NHibernateUtil.String.NullSafeGet(dr, names[0]);

            if (property0 == null)
            {
                return null;
            }

            IRiskState state;

            if (owner is Risk)
            {
                state =
                    (IRiskState)
                    Activator.CreateInstance(Type.GetType(typeof(IRiskState).Namespace + "." + (string)property0),
                                             owner);
            }
            else
            {
                state =
                    (IRiskState)
                    Activator.CreateInstance(Type.GetType(typeof(IRiskState).Namespace + "." + (string)property0));

            }

            return state;

        }

        public void NullSafeSet(System.Data.IDbCommand cmd, object value, int index)
        {
            if (value == null)
            {
                ((IDataParameter)cmd.Parameters[index]).Value = DBNull.Value;
            }
            else
            {
                var state = (IRiskState)value;
                ((IDataParameter)cmd.Parameters[index]).Value = state.GetType().Name;
            }
        }

        public object Replace(object original, object target, object owner)
        {
            return original;
        }

        public Type ReturnedType
        {
            get { return typeof(RiskState); }
        }

        public NHibernate.SqlTypes.SqlType[] SqlTypes
        {
            get { return new[] { NHibernateUtil.String.SqlType }; }
        }

        public new bool Equals(object x, object y)
        {
            if (x == null && y == null) return true;
            if (x == null || y == null) return false;
            return x.GetType() == y.GetType();
        }

        #endregion

    }
Using this on a property as follows:
 [Property(ColumnType = "Matlock.Core.Risks.RiskStateNameUserType, Matlock.Core")]
 public IRiskState RequiredState { get; set; }

 

We can now store types:

 

image

 

 

If importing from a file and we want to parse a string to our user type

 

        protected T GetCustomType<T>(XElement dsl, string attributeName)
        {
            string attribute = (string)dsl.Attribute(attributeName);
            var customType = (T)Activator.CreateInstance(Type.GetType(typeof(T).Namespace + "." + attribute));
            return customType;
        }