【发布时间】:2014-06-21 21:40:16
【问题描述】:
在我的项目中,我经常使用Linq's Sum()。它由 NHibernate on MySQL 提供支持。在我的 Session Factory 中,我明确要求 NHibernate 处理 decimals 时的小数点后 8 位:
public class DecimalsConvention : IPropertyConvention
{
public void Apply(IPropertyInstance instance)
{
if (instance.Type.GetUnderlyingSystemType() == typeof(decimal))
{
instance.Scale(8);
instance.Precision(20);
}
}
}
但是,我发现.Sum() 将数字四舍五入到小数点后 5 位:
var opasSum = opasForThisIp.Sum(x => x.Amount); // Amount is a decimal
在上面的语句中opaSum等于2.46914而应该是2.46913578(直接在MySQL上计算)。 opasForThisIp 的类型为 IQueryable<OutgoingPaymentAssembly>。
当涉及到decimals 时,我需要所有 Linq 计算来处理 8 位小数。
关于如何解决这个问题的任何想法?
编辑 1:我发现 var opasSum = Enumerable.Sum(opasForThisIp, opa => opa.Amount); 可以产生正确的结果,但问题仍然存在,为什么 .Sum() 会四舍五入结果,我们该如何解决?
编辑2:生成的SQL好像有问题:
select cast(sum(outgoingpa0_.Amount) as DECIMAL(19,5)) as col_0_0_
from `OutgoingPaymentAssembly` outgoingpa0_
where outgoingpa0_.IncomingPayment_id=?p0
and (outgoingpa0_.OutgoingPaymentTransaction_id is not null);
?p0 = 24 [Type: UInt64 (0)]
编辑 3:var opasSum = opasForThisIp.ToList().Sum(x => x.Amount); 也会产生正确的结果。
编辑 4:将 IQueryable<OutgoingPaymentAssembly> 转换为 IList<OutgoingPaymentAssembly> 使原始查询:var opasSum = opasForThisIp.Sum(x => x.Amount); 起作用。
【问题讨论】:
-
在运行
var opasSum = opasForThisIp.Sum(x => x.Amount);时,有没有检查生成的SQL语句? -
@DominicKexel 说得好,SQL语句确实有问题,看我的编辑。
-
我不明白。
.Sum()确实是Enumerable.Sum()的扩展方法,为什么会产生不同的SQL语句? -
opasForThisIp 是什么类型的?
-
如果您将 IQueryable 强制列在列表中,我很想知道生成的 SQL 会发生什么。 var opasSum = opasForThisIp.ToList().Sum(x => x.Amount);看起来应该和调用 Enumerable.Sum() 的效果一样,但我不能肯定。
标签: c# mysql linq nhibernate floating-point-precision