Some details on older post about usertype

In this old post I spoke about a user type that permits you to store a IList<String> property with nhibernate  in a single field of a database with a # separated list of string. That example did not contain the full code of the usertype, so here it is.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
 1     class StringListUserType : IUserType
 2     {
 3         private const char cStringSeparator = '#';
 4 
 5         #region Equals member
 6 
 7         bool IUserType.Equals(object x, object y)
 8         {
 9             if (x == null || y == null) return false;
10             IList<String> xl = (IList<String>) x;
11             IList<String> yl = (IList<String>) y;
12             if (xl.Count != yl.Count) return false;
13             Boolean retvalue =  xl.Except(yl).Count() == 0;
14             return retvalue;
15         }
16 
17         #endregion
18 
19         #region IUserType Members
20 
21         public object Assemble(object cached, object owner)
22         {
23             return cached;
24         }
25 
26         public object DeepCopy(object value)
27         {
28             IList<String> obj = (IList<String>)value;
29             List<String> retvalue =obj.ToList();
30 
31             return retvalue;
32         }
33 
34         public object Disassemble(object value)
35         {
36             return value;
37         }
38 
39         public int GetHashCode(object x)
40         {
41             return x.GetHashCode();
42         }
43 
44         public bool IsMutable
45         {
46             get { return true; }
47         }
48 
49         public object NullSafeGet(System.Data.IDataReader rs, string[] names, object owner)
50         {
51             List<String> result = new List<String>();
52             Int32 index = rs.GetOrdinal(names[0]);
53             if (rs.IsDBNull(index) || String.IsNullOrEmpty((String) rs[index]))
54                 return result;
55             foreach (String s in ((String)rs[index]).Split(cStringSeparator))
56                 result.Add(s);
57             return result;
58         }
59 
60         public void NullSafeSet(System.Data.IDbCommand cmd, object value, int index)
61         {
62             if (value == null || value == DBNull.Value)
63             {
64                 NHibernateUtil.String.NullSafeSet(cmd, null, index);
65             }
66             IEnumerable<String> stringList = (IEnumerable<String>) value;
67             StringBuilder sb = new StringBuilder();
68             foreach(String s in stringList) {
69                 sb.Append(s);
70                 sb.Append(cStringSeparator);
71             }
72             if (sb.Length > 0) sb.Length--;
73             NHibernateUtil.String.Set(cmd, sb.ToString(), index);
74         }
75 
76         public object Replace(object original, object target, object owner)
77         {
78             return original;
79         }
80 
81         public Type ReturnedType
82         {
83             get { return typeof(IList<String>); }
84         }
85 
86         public NHibernate.SqlTypes.SqlType[] SqlTypes
87         {
88             get { return new SqlType[] { NHibernateUtil.String.SqlType }; }
89         }
90 
91         #endregion
92     }

There are a couple of notes in this code, first of all the type IList<String> is a reference type, so the property IsMutable should return false. Then the IUserType.Equals method should  compare the two lists element by element. I’m really not interested about the order of the elements in the list, if I have a list (One , Two) in my domain it is equal to (Two, One), so I can use a linq Except operator to compare the values. If the order of the string really matters, you can do a compare element by element with a for loop. Remember also that the DeepClone method should return a new list identical to the original one, this because we are working with a reference type.

alk.

DotNetKicks Image