如何";降级“;C#十进制数据类型到任意小数位数?

如何";降级“;C#十进制数据类型到任意小数位数?,c#,linq,entity-framework-4,C#,Linq,Entity Framework 4,我有一个数据库表,其中有一个字段是以这样一种非常简化的形式定义的 CREATE TABLE Product ( ProductId INT, Price SMALLMONEY ) 我有一个LINQ实体框架查询,其简化形式如下: Iqueryable query = from Product in testDB.Products select new { Price = Product.Price } 问题

我有一个数据库表,其中有一个字段是以这样一种非常简化的形式定义的

CREATE TABLE Product
(
    ProductId INT,
    Price SMALLMONEY
)
我有一个LINQ实体框架查询,其简化形式如下:

Iqueryable query = from Product in testDB.Products
        select new
        {
            Price = Product.Price
        }
问题是,这会产生我在另一篇文章中描述的意外和不想要的行为

我已经对此进行了研究,并得出结论,这种不必要的行为是由于我的查询结果返回字段Price作为带4个小数点的小数。这是可以理解的,因为SMALLMONEY以4个小数点的精度存储在数据库中。 如果我减少小数的数量,一切正常。在这个小例子中类似的东西

Iqueryable query = from Product in testDB.Products
            select new
                {
                    Price = 1.12m;  // Decimal literal with 2 decimals
 }
所以我想把这个数字四舍五入到两位小数就足够了,我会没事的

Iqueryable query = from Product in testDB.Products
                select new
                {
                    Price = Decimal.Round(Products.Price,2) // round to two decimals    
                }

错。不知何故,价值价格仍然存在,它存储了4个小数点,而我的web表单被弄乱了

我查看了DecimalRound()的源代码

它通过引用传递参数值,所以我猜只有参数值发生了变化,而不是描述精度的内部“元数据”


我能做什么?如何将精度降低到两位小数。

如果没有更多上下文,建议将其转换为不同的数据类型:

select new 
{
    Price = (double) Products.Price
};
或字符串:

select new
{
    Price = Products.Price.ToString("##.00")
}

我怀疑问题在于您实际上没有使用
decimal.Round
执行舍入。相反,您在被转换为SQL的查询中表达它

如果希望取整在.NET中完成,则需要确保使用LINQ to对象,最简单的方法是调用
AsEnumerable
。例如:

var results = testDB.Products
    .Select(p => new { p.Name, p.Price })
    .AsEnumerable()
    .Select(p => new { p.Name, Price = decimal.Round(p.Price, 2) });
请注意,您应该确保在
AsEnumerable()
之前执行任何排序、筛选等操作,以避免将所有结果向下拉并在本地进行筛选


作为旁注,虽然没有简单的属性来获取比例、符号和有效位,但您可以使用来获取内部表示。这对于比较两个值是否相同很有用,有关更多详细信息,您可以参考文档,了解每一位的含义。

“错误。不知何故,值价格保留了存储4个小数点的知识,并且我的web表单被弄乱了。”请展示一个简短但完整的程序,以准确地说明您的意思。仅从您的描述很难区分。如果数据库中的类型为
SmallInt
,则实体中的类型不应为
decimal
@juharr Sorrry对不起。这是小钱。我会改正的。我注意力不集中。@JonSkeet我无法上传整个项目以及数据库aspx文件和这里的所有内容。在我的另一篇()文章中,我描述了有趣的行为。但通过测试,我把范围缩小到小数点,我不是建议你上传整个项目。我建议你创建一个简短但完整的程序来演示这个问题。这些是完全不同的事情。请看,将其转换为
double
是一个可怕的想法-这只是货币值的错误数据类型。如果他唯一的目的是向用户显示数据(无论如何都会转换为JS double),我认为这没有问题。不过,说到一般情况,你是对的。我认为我们必须同意不同意。这感觉就像是最终导致很难诊断错误的事情。这应该是可以修复的,同时坚持使用
decimal
类型。我也想坚持概念上正确的东西,但是如果你浪费大量时间试图修复违反逻辑的东西,这些变通方法是很诱人的。是的。我看过sql,你是对的。我的Decimal.Round(Product.Price)的sql值为Round([Project1].[Price],2)为[C4],因为Round(Decimal(S,P))的返回类型是Decimal(S,P),所以我得到的数据类型与原始数据相同。好的,现在我知道我是邪恶的根源。但我担心使用AsEnumerable()不是一个选项,因为我的网格使用动态分页、排序、筛选…@f470071:那么,基本上,在执行完查询的其余部分后,您需要找到其他方法来执行舍入。我不熟悉您正在使用的渲染库,但我相信这一定是可能的。Jon Skeet将我的注意力转向的是问题的根源。简而言之,我的Iqueryable中的Decimal.Round()被转换为SQL Round(),它输出与参数相同的十进制(s,p)类型。我已经在我的web组件级别修复了这个问题。接受并投票表决。Tnx。
var results = testDB.Products
    .Select(p => new { p.Name, p.Price })
    .AsEnumerable()
    .Select(p => new { p.Name, Price = decimal.Round(p.Price, 2) });