SQL Server to .Net Decimals with EF6 database first issue

Posted

技术标签:

【中文标题】SQL Server to .Net Decimals with EF6 database first issue【英文标题】:SQL Server to .Net Decimals with EF6 dDatabase first issue 【发布时间】:2019-09-27 15:55:43 【问题描述】:

我目前正在从 SQL Server 存储过程中读取数据,它返回为 Decimal(38, 20)

我知道 .Net 小数点是 (28, 10),但 EF 为此生成的模型类显示 Decimal?。当我查询表时,代码会引发转换溢出错误,因为它试图将 SQL Server 小数点放在 .Net 小数点字段中。

有没有一种简单的方法可以通过数据上下文将其转换为 .Net 十进制?基本上我无权修改 SQL Server 数据类型。

SQL Server 数据类型:

 Amount Decimal(38, 20)

实体

public class EntityClass

     public decimal? Amount  get; set; 

当我打电话时

 var eee =  _context.EntityClass
                    .Select(x => x.Amount)
                    .FirstOrDefaultAsync();

我明白了

转换溢出错误

【问题讨论】:

什么版本的 EF?您需要保留多少个有效数字?数据库中的什么值导致溢出? 这个肯定是个问题 (-4210862852.86000000000000000000)。 是的。我可以重现。什么版本的 EF? 为什么你不在课堂上使用 double ?公双?金额得到;放; @YairI double 不是just,它会让事情变得更糟。它的范围比 Decimal 并且保证会导致舍入错误。它也不会影响这个错误 - 字段的范围太长了 【参考方案1】:

这是 .NET 的 SqlClient 的错误或限制。这是一个再现:

    using (var con = new SqlConnection("server=.;database=tempdb;Integrated Security=true"))
    
        con.Open();
        var cmd = new SqlCommand("select cast(4210862852.86 as decimal(38,20))  val", con);
        using (SqlDataReader rdr = cmd.ExecuteReader())
        
            rdr.Read();

            var val = rdr.GetDecimal(0);
            Console.WriteLine(val);
        
    

问题是这个数字

select cast(cast(4210862852.86 as decimal(38,20)) as varbinary(20))

被存储,并通过网络传输

0x261400010000D877FB4DEE8B51699A5005000000

而且 SqlClient 将拒绝转换最后 4 个字节中任何非零的小数:

internal decimal Decimal

    get
    
        ThrowIfNull();

        if (StorageType.Decimal == _type)
        
            if (_value._numericInfo.data4 != 0 || _value._numericInfo.scale > 28)
            
                throw new OverflowException(SQLResource.ConversionOverflowMessage);
            
            return new decimal(_value._numericInfo.data1, _value._numericInfo.data2, _value._numericInfo.data3, !_value._numericInfo.positive, _value._numericInfo.scale);
        
        if (StorageType.Money == _type)
        
            long l = _value._int64;
            bool isNegative = false;
            if (l < 0)
            
                isNegative = true;
                l = -l;
            
            return new decimal((int)(l & 0xffffffff), (int)(l >> 32), 0, isNegative, 4);
        
        return (decimal)this.Value; // anything else we haven't thought of goes through boxing.
    

https://github.com/dotnet/corefx/blob/master/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlBuffer.cs

我在这里打开了一个针对 .NET Core 的问题:https://github.com/dotnet/corefx/issues/37592

【讨论】:

【参考方案2】:

您应该在 ApplicationDbContext 中添加

  protected override void OnModelCreating(ModelBuilder builder)
    
        base.OnModelCreating(builder);
        builder.Entity<EntityClass>()
            .Property(p => p.Amount )
            .HasColumnType("decimal(28,20)");

【讨论】:

“我无权修改 SQL Server 数据类型” OP的问题是数据库字段的精度38Decimal 最多可以处理 28 个。HasColumnType("decimal(28,20)") 也不会更改现有字段的精度,因此不会影响可以在那里存储的值。

以上是关于SQL Server to .Net Decimals with EF6 database first issue的主要内容,如果未能解决你的问题,请参考以下文章

HOW TO CHECK FOR ACTIVE TRACE FLAGS ON MICROSOFT SQL SERVER

翻译:Stairway to SQL Server Replication: Level 1 - Introduction to SQL Server Replication

Stairway to SQL Server Replication: Level 1 - Introduction to SQL Server Replication翻译,合并截图翻译

SSMS 远程连接SERVER 设置 - Unable to connect to SQL Server instance remotely

sql server to oracle

使用 SQL Server Compact Edition 的 Linq-to-SQL