20100315

Fluent NHibernate - List of Int as String

Having field of type List it is sometimes worthy to save it in database as string rather than create separate table just to keep few values per record.
It seems to be completely wrong from design point of view but can be much cleaner solution when you have just few values per record.

To map this easily in Fluent create just two classes.
Then just define your field as IList.

User type convention:
public class IntListConvention : IUserTypeConvention
    {
        public bool Accept(IProperty target)
        {
            return target.PropertyType == typeof(IList);
        }

        public void Apply(IProperty target)
        {
            target.CustomTypeIs(typeof(IntListUserType));
        }

        public bool Accept(Type type)
        {
            return type == typeof(IList);
        }
    }

And new user type:
class IntListUserType : IUserType
    {
        public new bool Equals(object x, object y)
        {
            return x != null && x.Equals(y);
        }

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

        object IUserType.NullSafeGet(IDataReader rs, string[] names, object owner)
        {
            string stringValue = (string) NHibernateUtil.String.NullSafeGet(rs, names[0]) ?? String.Empty;
            List result = new List();
            foreach (string stringItem in stringValue.Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries))
            {
                int item;
                if (Int32.TryParse(stringItem, out item))
                {
                    result.Add(item);
                }
            }
            return result;
        }

        public void NullSafeSet(IDbCommand cmd, object value, int index)
        {
            StringBuilder stringValue = new StringBuilder();
            List result = value as List;
            if (value != null)
            {
                foreach (int item in result)
                {
                    if (stringValue.Length > 0)
                    {
                        stringValue.Append(",");
                    }
                    stringValue.Append(item);
                }
            }
            ((IDataParameter)cmd.Parameters[index]).Value = stringValue.ToString();
        }

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

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

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

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

        public SqlType[] SqlTypes
        {
            get
            {
                return new[] { new SqlType(DbType.String, 1000) };
            }
        }

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

        public bool IsMutable
        {
            get
            {
                return false;
            }
        }
    }

No comments: