'Oracle.DataAccess manage c# byte fields as signed

Recently, adapting a .NET application to Oracle, I've found that the .net fields typed as byte, are updating (or inserting) in database as Signed Bytes, so a (byte)200 is set as -56 on the Oracle Column, that is defined as NUMBER(3,0) (due to legacy database definition).

Sample of wrong code:

var command = session.Session.Connection.CreateCommand();
command.CommandType = System.Data.CommandType.Text;
command.CommandText = "UPDATE MyTable SET TblByteCol = :parByte WHERE Id = 15";
var parameter = command.CreateParameter();
parameter.ParameterName = "parByte";
parameter.Value = (byte)200;
command.Parameters.Add(parameter);
var result = command.ExecuteNonQuery();

That code (similar) sets a -56 on TblByteCol. And when I try to get that value, it throws an OverflowException.

I'm using NHibernate (the above code is only to check that the problem is on driver) and I've found a solution defining a IUserType (from this SO Thread), but I would know (and understand) if is there any cleaner solution and more native solution. Perhaps an updated version of Oracle.DataAccess (I've been searching but no references found).

Versions:

  • .NET Framework: 4.0
  • Oracle.DataAccess: 4.112.1.0
  • NHibernate: 3.3.5.4

My solution

public class OracleUnsignedByte : IUserType
{
    public object Assemble(object cached, object owner)
    {
        return cached;
    }

    public object DeepCopy(object value)
    {
        return value;
    }

    public object Disassemble(object value)
    {
        return value;
    }

    public new bool Equals(object x, object y)
    {
        if (ReferenceEquals(x, y)) return true;

        if (x == null || y == null) return false;

        return x.Equals(y);
    }

    public int GetHashCode(object x)
    {
        return x == null ? typeof(string).GetHashCode() + 473 : x.GetHashCode();
    }

    public bool IsMutable
    {
        get { return false; }
    }

    public object NullSafeGet(System.Data.IDataReader rs, string[] names, object owner)
    {
        var obj = NHibernateUtil.String.NullSafeGet(rs, names[0]);

        if (obj == null) return null;

        short shortObj = Convert.ToInt16(obj);
        // Expected spanish format from DB
        if (shortObj < 0)
        {
            return Convert.ToByte(256 + shortObj); 
        }
        return Convert.ToByte(obj);
        //throw new SegTechnicalException(string.Format("Cannot convert string '{0}' to DateTime.", dateTimeStr));
    }

    public void NullSafeSet(System.Data.IDbCommand cmd, object value, int index)
    {
        if (value == null)
        {
            ((IDataParameter)cmd.Parameters[index]).Value = DBNull.Value;
        }
        else
        {
            ((IDataParameter)cmd.Parameters[index]).Value = (byte)value;
        }
    }

    public object Replace(object original, object target, object owner)
    {
        return original;
    }

    public Type ReturnedType
    {
        get { return typeof(byte); }
    }

    public NHibernate.SqlTypes.SqlType[] SqlTypes
    {
        get { return new[] { NHibernateUtil.String.SqlType }; }
    }
}



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source