尽管设置了精度,MSSQL 表中的小数仍会四舍五入

soo*_*mon 5 c# sql-server decimal entity-framework-core

我的 c# 对象有一个小数属性:

public decimal LastPrice { get; set; }
Run Code Online (Sandbox Code Playgroud)

在处理我的对象时,设置了十进制值。例如:

LastPrice = 0.091354;
Run Code Online (Sandbox Code Playgroud)

我修改了 DbContext 以提高小数精度,如另一篇 stackoverflow 帖子中所述:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{       
        foreach (var property in modelBuilder.Model.GetEntityTypes()
            .SelectMany(t => t.GetProperties())
            .Where(p => p.ClrType == typeof(decimal) || p.ClrType == typeof(decimal?)))
        {
            property.SetColumnType("decimal(38, 10)");
        }        
}
Run Code Online (Sandbox Code Playgroud)

Microsoft Sql Server Management Studio 中的表设计视图反映了此配置。这是从 SSMS 编写的表:

CREATE TABLE [dbo].[TradedCurrencyPairs](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [LastPrice] [decimal](38, 10) NOT NULL,
...
Run Code Online (Sandbox Code Playgroud)

当我在调试期间检查对象并将其添加到我的 DbContext 时,它看起来不错: 当我在调试期间检查对象并将其添加到我的 DbContext 时,它看起来不错

但在数据库中它最终为 0.0000000000。

据我所知,该值仍在四舍五入,就好像它的精度为 2 一样。本应为 0.09232 的值变成了 0.0900000000。所以所有小数仍然被削减。

我尝试了几种不同的数据注释:

// [PrecisionAndScale(20, 10)]
//[RegularExpression(@"^\d+\.\d{20,10}$")]
//[Range(0, 99999999999999999999.9999999999)]
[Range(typeof(decimal), "20", "10")]
Run Code Online (Sandbox Code Playgroud)

但他们没有帮助。从 SSMS 插入数据效果很好: INSERT INTO TradedCurrencyPairs VALUES ('tzt', 'ttt', 'rrrr', '20120618 10:34:09 AM' , 'hgghghg', 0.123456, 1, 0.123456789, 0.123456, 0.123456) ; 去

我的该列的 DbModelSnapshot 如下所示:

            b.Property<decimal>("LastPrice")
                .HasPrecision(10)
                .HasColumnType("decimal(20, 10)");
Run Code Online (Sandbox Code Playgroud)

我也尝试过:

TradedCurrencyPair TestPair = new TradedCurrencyPair("one", "two", "Bibox", DateTime.Now, "unknown", 0.1234567890M, 1, 0.1234567890M, 0.1234567890M, 0.1234567890M);
                context.TradedCurrencyPairs.Add(TestPair);
                context.SaveChanges(); 
Run Code Online (Sandbox Code Playgroud)

结果是一样的...

在设置值和最终进入数据库之间的某个地方,它会被修改:/

这是 SQL 表:

/****** Object:  Table [dbo].[TradedCurrencyPairs]    Script Date: 25/07/2020 09:32:32 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[TradedCurrencyPairs](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [TradedCurrency] [nvarchar](max) NULL,
    [BaseCurrency] [nvarchar](max) NULL,
    [Exchange] [nvarchar](max) NULL,
    [DateTime] [datetime2](7) NOT NULL,
    [TransactionType] [nvarchar](max) NULL,
    [LastPrice] [decimal](20, 10) NOT NULL,
    [ExchangeInternalPairId] [int] NOT NULL,
    [High24h] [decimal](20, 10) NOT NULL,
    [Low24h] [decimal](20, 10) NOT NULL,
    [Volume24h] [decimal](20, 10) NOT NULL,
 CONSTRAINT [PK_TradedCurrencyPairs] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
Run Code Online (Sandbox Code Playgroud)

不使用实体框架有效:

SqlCommand command = new SqlCommand("insert into TradedCurrencyPairs values('one', 'two', 'Bibox', convert(datetime, '18-06-12 10:34:09 PM', 5), 'unknown', 0.1234567890, 1, 0.1234567890, 0.1234567890, 0.1234567890); ", cnn);
This way the decimals do not get modified. So EF causes the issue.
Run Code Online (Sandbox Code Playgroud)

有人可以向我解释一下我做错了什么吗?

多谢!

soo*_*mon 3

当我从这里发布代码时:

Entity Framework Core - 将小数精度和小数位数设置为所有小数属性

我仍然习惯使用 EF Core 3,因此我启用了 EF Core 3 的代码。我不记得我使用了 beta 包并将它们更新为 EF Core 5 预览版。

所以使用这个:

    foreach (var property in modelBuilder.Model.GetEntityTypes()
        .SelectMany(t => t.GetProperties())
        .Where(p => p.ClrType == typeof(decimal) || p.ClrType == typeof(decimal?)))
    {
        
       // EF Core 3
       // property.SetColumnType("decimal(20, 10)");
       // property.SetPrecision(10);
        
        // EF Core 5
        property.SetPrecision(18);
        property.SetScale(6);
    }
Run Code Online (Sandbox Code Playgroud)

而不是这个:

    foreach (var property in modelBuilder.Model.GetEntityTypes()
        .SelectMany(t => t.GetProperties())
        .Where(p => p.ClrType == typeof(decimal) || p.ClrType == typeof(decimal?)))
    {
        
        EF Core 3
        property.SetColumnType("decimal(20, 10)");
        property.SetPrecision(10);
        
        // EF Core 5
        // property.SetPrecision(18);
        // property.SetScale(6);
    }
Run Code Online (Sandbox Code Playgroud)

工作完美。

很抱歉因为我的愚蠢错误而浪费了您的时间:/