C# Double与SQL Numeric精确等价转换及RDLC报表绑定冲突解决
解决RDLC报表中C# double?与SQL numeric(18,2)的绑定冲突问题
这个问题我之前处理过好几次,核心原因是C#的double(包括可空的double?)和SQL的numeric是完全不同语义的类型——double是浮点数(近似存储),而numeric是精确小数(定点存储),EF在默认情况下不会自动把这两种类型做映射,所以才会出现绑定失败的情况。
一、先明确:C#与SQL numeric的精确等价类型
SQL里的numeric(p,s)或者decimal(p,s),在C#里的精确等价类型是decimal(或者可空的decimal?),而不是double。两者都是定点数,能保证小数精度,非常适合财务类数据(比如你这里的收入报表金额)。用double的话会因为浮点数的近似特性导致精度丢失,绝对不推荐在财务场景使用。
二、具体解决方案(推荐最优方案)
最直接且正确的解决方式是修改你的模型类型,把ReportVm里的TotalAmount从double?改成decimal?:
public class ReportVm { // 原来的代码 // public double? TotalAmount { get; set; } // 修改为: public decimal? TotalAmount { get; set; } // 其他属性... }
修改之后,你的查询代码不需要做任何改动:
var result = Database.SqlQuery<ReportVm>("SP_InComeStatement @EntryDateFrom, @EntryDateTo", new SqlParameter("@EntryDateFrom", entryDateFromParam), new SqlParameter("@EntryDateTo", entryDateToParam)).ToList();
EF会自动把SQL返回的numeric(18,2)映射到decimal?上,绑定问题直接解决。
三、额外注意:RDLC报表的字段类型同步
修改模型之后,别忘了同步RDLC报表里对应的字段类型:
- 打开RDLC报表设计器,找到对应的数据集字段
- 把
TotalAmount的类型设置为Decimal(而不是原来的Double) - 如果报表里有表达式计算,也要确保用的是Decimal类型的运算,避免类型转换错误
四、如果暂时不能修改模型的替代方案(不推荐)
要是因为某些限制不能改模型类型,你可以在存储过程里把ReceivableAmount转换为浮点数返回,但强烈不建议这么做——因为会丢失精度,财务数据容不得半点误差:
-- 在存储过程里修改返回字段 CAST(ReceivableAmount AS FLOAT) AS ReceivableAmount
或者在C#查询时手动映射,但同样存在精度问题,而且代码更繁琐:
var tempResult = Database.SqlQuery<dynamic>("SP_InComeStatement @EntryDateFrom, @EntryDateTo", new SqlParameter("@EntryDateFrom", entryDateFromParam), new SqlParameter("@EntryDateTo", entryDateToParam)).ToList(); var result = tempResult.Select(t => new ReportVm { TotalAmount = (double?)t.ReceivableAmount, // 其他属性映射... }).ToList();
还是那句话,财务场景下绝对优先用decimal,别用double。
内容的提问来源于stack exchange,提问作者Sraban75
相关产品推荐
相关产品推荐

