In the db schema I’m currently working on, boolean values are represented by columns whose type is tinyint nullable (it’s SQL Server 2005). If such a value equals 1, then it is supposed to be True, 0 means False and if it is null then it is False, too.
This time I would like to show how to use NHibernate IUserType interface to enable automatic conversion from a database field to System.Boolean value
NHibernate.UserTypes.IUserType is a very useful interface when you are to handle some strange db schemas in your data access layer. As you can guess, the thing that we need is a class that implements this interface. You can see it below. The most important methods are NullSafeGet(…) and NullSafeSet(…) as they are responsible for conversion ‘logic’.
namespace MyNamespace { public class ByteAsBool : 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) { if (x == null) return 0; return x.GetHashCode(); } public bool IsMutable { get { return false; } } // represents conversion on load-from-db operations: public object NullSafeGet(System.Data.IDataReader rs, string[] names, object owner) { var obj = NHibernateUtil.String. NullSafeGet(rs, names[0]); if (obj == null) return false; byte b = 0; try { if (obj is string) b = byte.Parse(obj as string); else b = (byte)obj; } catch (Exception) { return false; } return b == 1; } // represents conversion on save-to-db operations: public void NullSafeSet(System.Data.IDbCommand cmd, object value, int index) { if (value == null) { ((IDataParameter)cmd.Parameters[index]).Value = DBNull.Value; } else { var boolValue = (bool)value; ((IDataParameter)cmd.Parameters[index]).Value = boolValue ? (byte)1 : (byte)0; } } public object Replace(object original, object target, object owner) { return original; } public Type ReturnedType { get { return typeof(bool); } } public NHibernate.SqlTypes.SqlType[] SqlTypes { get { return new[] { SqlTypeFactory.Byte }; } } #endregion bool IUserType.Equals(object x, object y) { return object.Equals(x, y); } } }
The class ByteAsBool can be now used in NHibernate mappings in the following way:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="SomeAssembly" namespace="MyNamespace.Types"> <class name="SomeClass" table="Some_Table" > <!-- ... --> <property name="active" column="ACTIVE" type="MyNamespace.ByteAsBool, SomeAssembly" access="field" /> <!-- ... --> </class> </hibernate-mapping>
The mapped class is very simple and looks very nice, as there are no ugly bool? types, just simple System.Boolean:
public class SomeClass : BaseEntity { protected bool active; // ... }