Search code examples
c#nhibernatenhibernate-mapping-by-codeusertype

nhibernate : read write list of string


I know I can read write list of string like below using nhibernate

HasMany(x => x.Attachments)
    .KeyColumn("RowId")
    .Table("PostTable").Element("PostKey");

But this creates an extra table, is there a way e.g. UserType or something else, so that we can directly write to list... if yes any example of custom UserType using nhibernate?? with sample code...

I also want that If i add value to list that also should be saved. I have seen below example code which breaks in case we add value to list...

   private virtual string StringValue
   public virtual IList<string> valueList
        { 
          get { return StringValue; }
          set { StringValue = string.Join(value, "|"); } 
         }

Solution

  • You can do this with IUserType like so:

    public class DelimitedList : IUserType
    {
        private const string delimiter = "|";
    
        public new bool Equals(object x, object y)
        {
            return object.Equals(x, y);
        }
    
        public int GetHashCode(object x)
        {
            return x.GetHashCode();
        }
    
        public object NullSafeGet(IDataReader rs, string[] names, object owner)
        {
            var r = rs[names[0]];
            return r == DBNull.Value 
                ? new List<string>()
                : ((string)r).SplitAndTrim(new [] { delimiter });
        }
    
        public void NullSafeSet(IDbCommand cmd, object value, int index)
        {
            object paramVal = DBNull.Value;
            if (value != null)
            {
                paramVal = ((IEnumerable<string>)value).Join(delimiter);
            }
            var parameter = (IDataParameter)cmd.Parameters[index];
            parameter.Value = paramVal;
        }
    
        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 SqlType[] { new StringSqlType() }; }
        }
    
        public Type ReturnedType
        {
            get { return typeof(IList<string>); }
        }
    
        public bool IsMutable
        {
            get { return false; }
        }
    }
    

    Then define the IList<string> property as type="MyApp.DelimitedList, MyApp".

    NOTE: SplitAndTrim is a string extension with various overrides that I created. Here is the core method:

    public static IList<string> SplitAndTrim(this string s, StringSplitOptions options, params string[] delimiters)
        {
            if (s == null)
            {
                return null;
            }
            var query = s.Split(delimiters, StringSplitOptions.None).Select(x => x.Trim());
            if (options == StringSplitOptions.RemoveEmptyEntries)
            {
                query = query.Where(x => x.Trim() != string.Empty);
            }
            return query.ToList();
        }