【问题标题】:Inserting small float value to SQL Server using C# and Entity Framework使用 C# 和实体框架将小浮点值插入 SQL Server
【发布时间】:2016-08-23 05:50:33
【问题描述】:

我的代码是这样的。

public class MyDbContext : DbContext
{
    public virtual DbSet<CurrentData> CurrentData { get; set; }
}

public class CurrentData
{
    public int ID { get; set; }
    public DateTime Time { get; set; }
    public float Value { get; set; }
}

...

float f = 1.37E-40f;

using (var context = new MyDbContext())
{
    var data = new CurrentData() { ID = 100, Time = DateTime.Now, Value = f };
    context.CurrentData.Add(data);

    var result = context.SaveChanges();
}

它在SaveChanges() 上引发异常,因为浮点值很小。

传入的表格数据流 (TDS) 远程过程调用 (RPC) 协议流不正确。参数 4 (\"@1\"):提供的值不是真实数据类型的有效实例。检查源数据中的无效值。一个无效值的例子是小数位数大于精度的数值类型数据。

如果我将f 更改为0,它可以正常工作。

当我检查 SQL Server 的 REAL 类型范围时,最小正值为 1.18E-38。

https://msdn.microsoft.com/en-us/library/ms173773.aspx

所以如果C#中的float值小于1.18E-38,就会发生异常。

我像这样更改了f

if (f > 0 && f < 1.18E-38f)
    f = 0;
else if (f < 0 && f > -1.18E-38f)
    f = 0;

但我觉得不好看。

什么是更好的解决方案?

我使用SqlDataAdapter 而不是实体框架进行了测试,得到了同样的异常。

我在 SQL Server 2012 中使用了 EF v6.1.3 和 .NET 4.5.1。

【问题讨论】:

  • 如果你只存储“数字”而不需要计算mssql中的数字,你也许可以将它存储为字符串文字? msdn.microsoft.com/en-us/library/sd9e25kz(v=vs.110).aspx
  • @montewhizdoh 因为没有必要这样做。 SQL Server 确实具有具有明确定义的比例和精度的numeric 类型,例如numeric(19,5)
  • 只是不要使用floatreal。在表上使用具有所需比例和精度的数字类型,在类上使用decimal。另一方面,为什么要使用这么小的数字?你想模拟一个 NULL 吗?
  • @Panagiotis 你将如何存储 numeric(800,799) ?你没做过很多回归计算吧?
  • @montewhizdoh 我不知道。我询问了这种奇怪要求的原因。 OP 很可能正在尝试解决不同的问题,并认为存储一个小浮点数是解决方案。例如,代码和/或数据库不使用十进制/数字导致缩放错误。 OP 可能不得不使用一个小值而不是 0 进行比较。 real 解决方法是为所有数字字段定义适当的比例,并在需要时与 0 进行比较

标签: c# sql-server entity-framework


【解决方案1】:

这里的问题是 C# 在 x86 架构上运行时支持非规范化浮点值,而 SQL Server 不支持。因此,C# float 比 SQL Server REAL 支持更多的值,即使两者名义上都是单精度浮点类型。 (更令人困惑的是,SQL Server 调用的FLOAT 实际上是双精度类型,C# 调用double,所以float != FLOAT——但这不是这里的问题)。

在 C# 中无法禁用非规范化值,也没有非常好的方法来测试它们。不过,This question 在答案中有一些方法。另一种方法当然是将SQL Server端的列精度提高到FLOAT;这可以处理 C# float 范围内的所有值,甚至是非规范化的。当然,当您从数据库中读取不适合float 的值时,这只会转移问题。当您需要存储 C# double 时,它没有任何解决方案,因为 SQL 端没有相应的更大类型。

出于实际目的,一个简单的范围检查可能就足够了,特别是如果您可以将它与您的应用程序实际使用的范围联系起来。

【讨论】:

  • 您认为转换代码在用户代码中是否正确?我认为大多数用户可能会将 c# float 视为 sql 真实类型,这意味着它在这种情况下存在潜在问题。我认为在 EF 或 SqlDataAdapter 中应该有一些选项可以忽略这一点。
  • 用户不能忽视 C# 数据类型和 SQL Server 数据类型之间的差异。例如,C# DateTime 支持值 0001-01-01,SQL DATETIME 不支持。你不能只是“忽略”这样的范围问题。但我不是 EF 的作者,关于这个的讨论对于 SO 来说是相当离题的。您可以随时打开 EF 项目的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-19
  • 2015-07-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多