Home > .Net, C#, NHibernate > NHibernate working with Unsigned Value types like uint, sbyte, short etc.

NHibernate working with Unsigned Value types like uint, sbyte, short etc.

NHibernate working with Unsigned Value types like uint, sbyte, short etc.

We want to share one of the first experiences during developing with NHibernate. We immediately bumped in to serious problem with supporting unsigned Value types like

uint, ulong, sbyte

etc .  Natively those types are not fully supported by NHibernate.

You probably will ask “why we need those types?” Data that comes in some special formatting binary way form streaming where packet size is very important, so many optimizations are used. Our task was deserialize those compressed messages and at the end all data have to be stored in database tables. Additional that affected on our solution was demand to serialize data back to binary format from database tables.

The simplest and fast solutions were to duplicate properties int and uint but this was very ugly and not developer friendly proposal (from our point of view of cause). Additionally we have had plenty of such unsigned fields.

private uint m_value;

 

private int VlaueInt

{

get{ return (int)m_value;}

set { m_value = (uint)value; }

}

 

 

public uint ValueUint

{

get { return m_value; }

set { m_value = value; }

}

The second option were implementation of IUserType which means I have to create type that NHibernate can work with, but this solution wasn’t an option for us as well, because we didn’t wanted that our users that are going to use those Types will be aware of NHibernate existence. What will happen if we will choose to move all our data model to Entity framework for example.

Finally we agreed on following solution that best suits for our needs and design,

We will override Getters and Setters of each entity object that Mapped to DB by NHibernate mapping files.

Example .hbm mapping file where we are providing our own Getter ans Setter implementation instead of default:

<property name=ItemID column=ITEMID access=DataTransfer.UInt32PropertyAccessor, DataTransfer type=long not-null=true/>


In order to make some generalization on the process we have declared Abstract class that implements ISetter and IGetter interfaces.

See following code:

/// <summary>

/// Abstract class representing basic Setter

/// </summary>

public abstract class MySetter : ISetter

{

#region Data Members

/// <summary>

/// Holds the property that currently has been running

/// </summary>

protected readonly String _propertyName;

protected readonly Type m_currentSetterType;

protected PropertyInfo m_property;

#endregion Data Members

//—————————————–

#region ISetter Members

 

public MySetter(string propertyName, Type theClass)

{

_propertyName = propertyName;

m_currentSetterType = theClass;

}

 

/// <summary>

/// Sets the specified target.

/// </summary>

/// <param name=”target”>The target.</param>

/// <param name=”value”>The value.</param>

public virtual void Set(object target, object value)

{

if (CheckSetNullable(value, ref target))

{

return;

}

InternalSet(target, value);

}

protected abstract void InternalSet(object target, object value);

 

 

protected virtual void SetValue(ref object target, uint uintVal)

{

Property.SetValue(target, uintVal, null);

}

/// <summary>

/// Checks the value equality.

/// </summary>

/// <typeparam name=”T”></typeparam>

/// <param name=”target”>The target.</param>

///

/// <returns></returns>

protected virtual T CheckValueEquality<T>(object target)

{

T currVal = default(T);

if (Property.GetValue(target, null) == null)

{

return currVal;

}

currVal = (T)Property.GetValue(target, null);

 

return currVal;

}

/// <summary>

/// Checks the set nullable.

/// </summary>

/// <param name=”value”>The value.</param>

/// <param name=”target”>The target.</param>

/// <returns>True if there was Nullable type care</returns>

protected bool CheckSetNullable(object value, ref object target)

{

if (value == null)

{

 

object obj = Property.GetValue(target, null);

if(obj != null)

Property.SetValue(target, null, null);

return true;

}

return false;

}

#endregion

 

#region ISetter Members

 

public virtual System.Reflection.MethodInfo Method

{

get { return null; }

}

 

public virtual string PropertyName

{

get { return _propertyName; }

}

 

#endregion

 

/// <summary>

/// Gets the property.

/// </summary>

/// <value>The property.</value>

public PropertyInfo Property

{

get

{

if(m_property == null)

m_property = m_currentSetterType.GetProperty(_propertyName);

return m_property;

}

}

}

 

/// <summary>

///

/// </summary>

/// <typeparam name=”T”></typeparam>

internal class MyGetter<T> : IGetter //where T : struct

{

protected readonly String _propertyName;

protected readonly Type m_currentSetterType;

protected PropertyInfo m_property;

 

public MyGetter(String propertyName, Type theClass)

{

_propertyName = propertyName;

m_currentSetterType = theClass;

 

}

 

#region IGetter Members

 

public virtual object Get(object target)

{

return Property.GetValue(target, null); ;

}

 

public object GetForInsert(object owner, System.Collections.IDictionary mergeMap, NHibernate.Engine.ISessionImplementor session)

{

throw new NotImplementedException();

}

 

public System.Reflection.MethodInfo Method

{

get { return null; }

}

 

public string PropertyName

{

get { return _propertyName; }

}

 

public Type ReturnType

{

get { return typeof(T); }

}

 

#endregion

/// <summary>

/// Gets the property.

/// </summary>

/// <value>The property.</value>

public PropertyInfo Property

{

get

{

if (m_property == null)

m_property = m_currentSetterType.GetProperty(_propertyName);

return m_property;

}

}

}

 

Example of concrete usage:

 

//—————————-

/// <summary>

///

/// </summary>

/// <typeparam name=”T”></typeparam>

internal class ByteGetter<T> : MyGetter<T> //where T : System.UInt16

{

 

public ByteGetter (String propertyName, Type theClass)

: base(propertyName, theClass)

{

}

 

#region IGetter Members

 

public override object Get(object target)

{

PropertyInfo property = target.GetType().GetProperty(_propertyName);

object val = property.GetValue(target, null);

if (val != null && val.GetType() == typeof(byte))

{

short intVal = (byte)val;

return intVal;

}

return val;

}

#endregion

}

 

 

We have used Factory design pattern in order to create custom concrete setters, this our personal implementation – we think it’s the right way to do it.

 

internal static class PropertyAccessorFactory

{

 

public static MyISetter GetPropertySetter<T>(string propertyName, Type theClass)

{

switch (typeof(T).Name)

{

case “UInt32”:

return new UintSetter(propertyName, theClass);

break;

case “UInt16”:

return new UShortSetter(propertyName, theClass);

break;

case “SByte”:

return new SByteSetter(propertyName, theClass);

break;

case “Byte”:

return new ByteSetter(propertyName, theClass);

break;

default:

throw new ArgumentOutOfRangeException(“[PropertyAccesorFactory] type not supported “ + typeof(T).Name);

}

}

}

 

Finally we need to implement our own PropertyAccessor class where we are deciding which Getter and Setter to provide. Here comes the Factory which described above usage.

 

#region UInt16PropertyAccessor Class

/// <summary>

/// Manages conversions from long to uint

/// </summary>

class UInt16PropertyAccessor : IPropertyAccessor

{

#region IPropertyAccessor Members

 

public bool CanAccessTroughReflectionOptimizer

{

get { return true; }

}

 

public IGetter GetGetter(Type theClass, string propertyName)

{

return new UShortGetter<ushort>(propertyName, theClass);

}

 

public ISetter GetSetter(Type theClass, string propertyName)

{

return PropertyAccessorFactory.GetPropertySetter<ushort>(propertyName, theClass);

}

#endregion

}

#endregion

 

That’s it, there is lots of code hope you are able to navigate inside of our classes and methods. Mostly its implementation mandatory methods for NHibernate Getters and setters classes.

Enjoy 🙂

Categories: .Net, C#, NHibernate Tags:
  1. No comments yet.
  1. No trackbacks yet.