Stu
Stu

Reputation: 2446

Map SQLDecimal property in NHibernate

I'm trying to read a decimal (38,16) from a SQL Server DB and struggling. After much reading around I'm trying to implement a custom type for SQL Decimal with the following code:

public class BigDecimal : IUserType
    {
        public bool Equals(object x, object y)
        {
            return object.Equals(x,y);
        }

        public int GetHashCode(object x)
        {
            return x.GetHashCode();
        }

        public object NullSafeGet(IDataReader rs, string[] names, object owner)
        {
            int index = rs.GetOrdinal(names[0]);
            object result = rs.GetValue(index);
            return result;
        }

        public void NullSafeSet(IDbCommand cmd, object value, int index)
        {
            //Not got here yet
        }

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

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

        public object Assemble(object cached, object owner)
        {
            return cached;
        }

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

        public SqlType[] SqlTypes { get { return new[] {SqlTypeFactory.Decimal}; } }
        public Type ReturnedType { get { return typeof (SqlDecimal); } }
        public bool IsMutable { get { return false; } }
    }

but the output of rs.GetValue is a decimal not at SQLDecimal which causes an OverflowException.

The class looks like this:

public class Billy
{
    public BigDecimal TheNumber {get;set;}
}

and the mapping looks like this:

public class BillyMap : ClassMap<Billy>
{
    public BillyMap()
    {
        Map(b=>b.TheNumber).CustomType<BigDecimal>();
    }
}

Please can someone tell me where I'm going wrong.

Upvotes: 1

Views: 144

Answers (2)

Stu
Stu

Reputation: 2446

In the end I made a something which performs a convert in the SQL and made it a Property Part and just use it on all the mapping files:

    private const string DECIMAL_CONVERSION = "(CONVERT(decimal(28,6), [{0}]))";

    private static string MapDecimalProperty(string fieldName)
    {
        return string.Format(DECIMAL_CONVERSION, fieldName.Trim('[',']'));
    }

    public static PropertyPart LongDecimal(this PropertyPart part, string fieldName)
    {
        return part.Formula(MapDecimalProperty(fieldName));
    }

the on the mapping:

Map(ep => ep.BigDecimalField).EDWDecimal("[BigDecimalField]");

this works for now. I've informed the data architecture team that this is happening and they don't think that it will be a problem with any current data and will consider it for future developments.

Upvotes: 0

Oskar Berggren
Oskar Berggren

Reputation: 5629

I think you need to cast the reader to SqlDataReader so you can access either GetSqlDecimal() or GetSqlValue(), as GetValue() will convert to a basic .Net Framework type. From 'https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldatareader.getsqlvalue%28v=vs.110%29.aspx':

GetSqlValue returns data using the native SQL Server types. To retrieve data using the .NET Framework types, see GetValue.

Upvotes: 1

Related Questions