Eloquent将十进制数转换为字符串

28

我在Eloquent模型中使用了一个小数位字段来表示货币,但是当我尝试将某些数字添加到该字段时,发现结果错误。

进一步检查后,我发现小数位字段被强制转换为字符串,如tinker控制台中的"1245114.00"

我检查了表结构,并可以确认该字段确实为decimal(11,3)

这个问题曾经在Stack Overflow上被提问过,但没有答案。

为什么会发生这种情况?


https://mattstauffer.com/blog/laravel-5.0-eloquent-attribute-casting/ - Luis felipe De jesus Munoz
数据库中的列类型是什么? - PULL STACK DEV
@AdnanMumtaz 十进制数 - Sapnesh Naik
5个回答

53

您需要在模型中定义哪些字段需要转换为基元属性。

protected $casts = [
    'my_decimal' => 'float',
];

在您的模型上,$casts 属性提供了一种将属性转换为常见数据类型的便捷方法。 $casts 属性应该是一个数组,其中键是要转换的属性名称,值是您希望将列转换为的类型。 支持的转换类型包括:integerrealfloatdoublestringbooleanobjectarraycollectiondatedatetimetimestamp

这里有一个非常好的解释:

https://mattstauffer.com/blog/laravel-5.0-eloquent-attribute-casting/

还有文档中的解释:

https://laravel.com/docs/5.5/eloquent-mutators#attribute-casting


11
如果我使用浮点数或双精度数处理货币,那么在处理过程中进行的计算操作是否会违背使用 DECIMAL 字段存储金额的初衷?请原谅我是否问了一个愚蠢的问题,但是十进制(decimal)不是比浮点数更好地处理货币吗? - Sapnesh Naik
2
另一个想法是将其存储为以分为单位的整数,并在需要呈现值时进行转换。 - common sense
2
@commonsense 如果只处理小数字,那是个好主意。请记住,int通常是一个数字的32位表示,因此它可以存储的最大数字是2,147,483,647。因此,当以分为单位存储数百万(例如),程序将会崩溃。 - Luis felipe De jesus Munoz
1
作为一个已经构建了大量带有会计功能的网络应用程序/客户关系管理系统的人,最好将货币以INT的形式存储。 - Matt Wohler
2
随着SQL的BIGINT类型以及系统普遍向64位架构转移,我认为溢出不再是一个大问题。8字节整数可以表示高达9万亿的值,因此除非您使用的是2008年津巴布韦货币,否则您不应该使用小单位方法溢出。 - alexw
显示剩余2条评论

9
根据Laravel的github存储库上的此线程: https://github.com/laravel/framework/issues/11780 看起来是PDO驱动程序的问题,会自动将小数转换为字符串。 该线程中的人们说这是mysql 5.2驱动程序的问题,有些人回滚到了5.1。如果您在自己的服务器上,则可以降级。 否则,您将不得不在模型层次上将其强制转换为浮点数。

6

由于PHP没有小数类型,所以这是应该的。如果您将小数转换为浮点数,可能会丢失精度。

最好的选择是将其保留为字符串,然后使用bcmath进行操作,bcmath是用于处理字符串的。


5

我刚花了一些时间分析这个问题,因为我的 Laravel 模型将数据库十进制列显示为字符串。

重要的是,在模型中添加浮点数类型转换确实可以解决该问题,但如果像我一样,您会注意到在模型添加类型转换后,dd(\ App \ SomeModel :: someScope() - > get()) 仍然显示那些十进制列作为字符串。

当这些值被发送到客户端时,它们是整数,因此类型转换确实解决了原始问题,从而使我的 JavaScript 收到 Number 而不是 String

我只是提供这个答案,所以一个人不会因为专注于 dd() 输出而浪费时间。我研究了关于 PDO 驱动程序的解决方案,虽然有些也许有价值,但这并不是很重要,因为真正的数据库输出已被转换为正确的类型。


0
还要注意,0.000会给你一个真值。
为了获取其数值或进行比较:
或者
$value = +$model->number_field_decimal

或者

$value = 1*$model->number_field_decimal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接