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;
// ...
}