Mapping Strings to Booleans Using NHibernate’s IUserType
Update: I failed to realized that the functionality of converting “Y” or “N” to a boolean is already built into NHibernate by doing type=”YesNo” (see comments). I’ll leave this post up just for the academics of creating a IUserType. Go figure that I would come up with something that’s built in!
We have some legacy data where boolean values are stored as strings. “Y” is true and “N” is no. We’re also creating entities which have properties that map to this data. It would be just plain evil to have to create all the boolean properties as strings! We previously solved this problem by creating our own .NET type that had a string property for the “Y” or “N” value. This type had an implicit cast defined as a bool, so we could treat it as a boolean in expressions and assignments. We mapped this in NHibernate as a component with the single string property and this worked pretty well, but I suspected that there was a better way. Today I bought the e-book version of NHibernate in Action and quickly read through the section on creating an implementation of IUserType. I then came up with the following class that allows me to keep my types as true booleans in the code.
public class YesNoType : IUserType { public bool IsMutable { get { return false; } }<span style="color: #0000ff">public</span> Type ReturnedType { get { <span style="color: #0000ff">return</span> <span style="color: #0000ff">typeof</span>(YesNoType); } } <span style="color: #0000ff">public</span> SqlType[] SqlTypes { get { <span style="color: #0000ff">return</span> <span style="color: #0000ff">new</span>[]{NHibernateUtil.String.SqlType}; } } <span style="color: #0000ff">public</span> <span style="color: #0000ff">object</span> NullSafeGet(IDataReader rs, <span style="color: #0000ff">string</span>[] names, <span style="color: #0000ff">object</span> owner) { var obj = NHibernateUtil.String.NullSafeGet(rs, names[0]); <span style="color: #0000ff">if</span>(obj == <span style="color: #0000ff">null</span> ) <span style="color: #0000ff">return</span> <span style="color: #0000ff">null</span>; var yesNo = (<span style="color: #0000ff">string</span>) obj; <span style="color: #0000ff">if</span>( yesNo != <span style="color: #006080">"Y"</span> && yesNo != <span style="color: #006080">"N"</span> ) <span style="color: #0000ff">throw</span> <span style="color: #0000ff">new</span> YourException(<span style="color: #006080">"Expected data to be 'Y' or 'N' but was '{0}'."</span>, yesNo); <span style="color: #0000ff">return</span> yesNo == <span style="color: #006080">"Y"</span>; } <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> NullSafeSet(IDbCommand cmd, <span style="color: #0000ff">object</span> <span style="color: #0000ff">value</span>, <span style="color: #0000ff">int</span> index) { <span style="color: #0000ff">if</span>(<span style="color: #0000ff">value</span> == <span style="color: #0000ff">null</span>) { ((IDataParameter) cmd.Parameters[index]).Value = DBNull.Value; } <span style="color: #0000ff">else</span> { var yes = (<span style="color: #0000ff">bool</span>) <span style="color: #0000ff">value</span>; ((IDataParameter)cmd.Parameters[index]).Value = yes ? <span style="color: #006080">"Y"</span> : <span style="color: #006080">"N"</span>; } } <span style="color: #0000ff">public</span> <span style="color: #0000ff">object</span> DeepCopy(<span style="color: #0000ff">object</span> <span style="color: #0000ff">value</span>) { <span style="color: #0000ff">return</span> <span style="color: #0000ff">value</span>; } <span style="color: #0000ff">public</span> <span style="color: #0000ff">object</span> Replace(<span style="color: #0000ff">object</span> original, <span style="color: #0000ff">object</span> target, <span style="color: #0000ff">object</span> owner) { <span style="color: #0000ff">return</span> original; } <span style="color: #0000ff">public</span> <span style="color: #0000ff">object</span> Assemble(<span style="color: #0000ff">object</span> cached, <span style="color: #0000ff">object</span> owner) { <span style="color: #0000ff">return</span> cached; } <span style="color: #0000ff">public</span> <span style="color: #0000ff">object</span> Disassemble(<span style="color: #0000ff">object</span> <span style="color: #0000ff">value</span>) { <span style="color: #0000ff">return</span> <span style="color: #0000ff">value</span>; } <span style="color: #0000ff">public</span> <span style="color: #0000ff">new</span> <span style="color: #0000ff">bool</span> Equals(<span style="color: #0000ff">object</span> x, <span style="color: #0000ff">object</span> y) { <span style="color: #0000ff">if</span>( ReferenceEquals(x,y) ) <span style="color: #0000ff">return</span> <span style="color: #0000ff">true</span>; <span style="color: #0000ff">if</span>( x == <span style="color: #0000ff">null</span> || y == <span style="color: #0000ff">null</span> ) <span style="color: #0000ff">return</span> <span style="color: #0000ff">false</span>; <span style="color: #0000ff">return</span> x.Equals(y); } <span style="color: #0000ff">public</span> <span style="color: #0000ff">int</span> GetHashCode(<span style="color: #0000ff">object</span> x) { <span style="color: #0000ff">return</span> x == <span style="color: #0000ff">null</span> ? <span style="color: #0000ff">typeof</span>(<span style="color: #0000ff">bool</span>).GetHashCode() + 473 : x.GetHashCode(); }}
The mapping looks something like:
<property name="Active" type="NHTypes.YesNoType, NHTypes" column="ACTIVE_YN" not-null="false" />
I’m not going to go into detail and explain what all the parts are and do (see link), but I thought that I would share the class. Please let me know if you spot any problems.
