在NHibernate中映射SQLDecimal属性

时间:2015-04-10 09:26:11

标签: nhibernate fluent-nhibernate nhibernate-mapping fluent-nhibernate-mapping custom-type

我正在尝试从SQL Server数据库读取小数(38,16)并且苦苦挣扎。经过大量阅读后,我正在尝试使用以下代码实现SQL Decimal的自定义类型:

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

但是rs.GetValue的输出是一个小数而不是SQLDecimal,这会导致OverflowException。

该课程如下:

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

,映射如下所示:

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

请有人告诉我我哪里出错了。

2 个答案:

答案 0 :(得分:1)

我认为您需要将阅读器强制转换为SqlDataReader,以便可以访问GetSqlDecimal()或GetSqlValue(),因为GetValue()将转换为基本的.Net Framework类型。来自“https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldatareader.getsqlvalue%28v=vs.110%29.aspx”:

  

GetSqlValue使用本机SQL Server类型返回数据。要使用.NET Framework类型检索数据,请参阅GetValue。

答案 1 :(得分:0)

最后,我创建了一个在SQL中执行转换并使其成为属性部分并在所有映射文件上使用它的东西:

    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));
    }

关于映射:

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

这适用于现在。我已经告知数据架构团队这种情况正在发生,他们并不认为这将是任何当前数据的问题,并会考虑将来的发展。