【问题标题】:Access database doesn't save decimal values correctlyAccess 数据库未正确保存十进制值
【发布时间】:2015-01-12 11:52:23
【问题描述】:

我在尝试将十进制值保存在我的 Access 数据库中的表中时遇到了一些问题。

如果我键入这些值,没有问题,但是当我尝试使用我的程序保存它们时,数据库不会保存小数并删除,(8,7 变成 87)。

表格中的字段是小数、小数位数 2、精度 8 和小数位数 2。

我正在使用此代码插入数据:

Dim price as Decimal
ProductsTableAdapter.Insert(id,name,price)

我也尝试将价格设置为double,但我仍然遇到同样的问题。

我查看了很多地方并阅读了有关将 Access DB 上的数据类型更改为 Double 的信息,但没有成功。

任何想法都将不胜感激!

编辑:

正如cybermonkey 所说,Decimal 的值是8,7,所以我尝试以这种方式进行更改。

我更改了代码以将, 替换为.

Dim price2 As String
price2 = price.ToString.Replace(",", ".")
ProductTableAdapter.Insert(id, name, price2)

价格 2 是 8.7,但数据库再次显示 87,00

编辑 2:

我试图用不同的数据库创建另一个项目来确定问题是否是这个特定的适配器,但我又遇到了同样的问题。

之后,我调试程序以查看十进制值是如何存储的,并且是:8,7 而不是8.7。然后我尝试在数据库上插入数据,如果你输入8.78,7,它与这两个值一起工作正常,所以现在我不知道为什么这不起作用。

【问题讨论】:

  • 问题似乎是您的本地化,Decimal 值有句号(通常),但您使用的是逗号。您的本地化(系统语言)是什么?
  • 我尝试在 DB 和 VB 程序上同时使用 Decimal 和 Double。
  • 问题在于 .NET 处理本地化的方式,请参阅我的答案以获取更多信息和示例代码(示例代码适用于 SQL,但您应该能够转换为读取 Access 数据库)。
  • 我一直在研究这个问题,我发现它令人困惑。我将研究它,然后在找到解决方案时更新我的​​答案。
  • 硬编码它以更改逗号和点不是如何转换十进制值。您需要回答第一个问题:您的系统文化设置是什么?数据是相同格式还是来自不同文化?

标签: vb.net ms-access decimal


【解决方案1】:

我已经能够重现该问题。在 Windows 系统区域设置不使用句点字符 (.) 作为十进制符号的计算机上运行时,这似乎是 Access OLEDB 提供程序的“不幸功能”。

使用以下代码

Dim price As Decimal = Convert.ToDecimal("8,7")
Dim sb As New System.Text.StringBuilder("""price"" is a ")
sb.Append(price.GetType.FullName)
sb.Append(" whose value is ")
If price < 1 Or price > 10 Then
    sb.Append("NOT ")
End If
sb.Append("between 1 and 10.")
Debug.Print(sb.ToString)

ProductsTableAdapter.Insert("myProduct", price)

当我在 Windows 设置为“英语(美国)”的情况下运行它时,我看到了调试输出

"price" is a System.Decimal whose value is NOT between 1 and 10.

并且值 87 被插入到数据库中,因为字符串“8,7”在该语言环境中不是有效的小数。

Windows 设置为“西班牙语(西班牙)”时,现在会生成相同的代码

"price" is a System.Decimal whose value is between 1 and 10.

但值 87 仍被插入。

Windows 设置为“法语(加拿大)”时,调试输出相同

"price" is a System.Decimal whose value is between 1 and 10.

但是,插入失败并显示“标准表达式中的数据类型不匹配”。

通过替换得到完全相同的结果

ProductsTableAdapter.Insert("myProduct", price)

Dim myConnStr As String
myConnStr =
        "Provider=Microsoft.ACE.OLEDB.12.0;" &
        "Data Source=C:\Users\Public\Database1.accdb"
Using con As New OleDbConnection(myConnStr)
    con.Open()
    Using cmd As New OleDbCommand("INSERT INTO Products ([name], price) VALUES (?,?)", con)
        cmd.Parameters.AddWithValue("?", "oledbTest")
        cmd.Parameters.AddWithValue("?", price)
        cmd.ExecuteNonQuery()
    End Using
End Using

证明这是System.Data.OleDb 和Access OLEDB 提供程序之间的问题,而不仅仅是TableAdapter 的特性。但是,TableAdapter 似乎完全依赖于 OleDb,因此很遗憾,它们可能无法在这些条件下工作。

好消息是,简单地将 OleDb 代码转换为 Odbc 似乎已经解决了“西班牙语(西班牙)”和“法语(加拿大)”Windows 语言环境的问题

Dim myConnStr As String
myConnStr =
        "Driver={Microsoft Access Driver (*.mdb, *.accdb)};" &
        "DBQ=C:\Users\Public\Database1.accdb"
Using con As New OdbcConnection(myConnStr)
    con.Open()
    Using cmd As New OdbcCommand("INSERT INTO Products ([name], price) VALUES (?,?)", con)
        cmd.Parameters.AddWithValue("?", "odbcTest")
        cmd.Parameters.AddWithValue("?", price)
        cmd.ExecuteNonQuery()
    End Using
End Using

因此一种可能的解决方法是使用 OdbcDataAdapter 而不是 TableAdapter。

【讨论】:

  • 感谢您的回答,我会尽快测试。
  • 我在 con.Open() 上收到 obdcException:error im002 microsoft odbc driver manager data source name not found and no default driver specified
  • 试试Driver={Microsoft Access Driver (*.mdb)}(不带“, .accdb”位​​)看看是否有帮助。如果没有,请打开 new question 并提供详细信息。
  • 完全扯掉了我的答案。
【解决方案2】:

问题似乎是 .NET 期望您为 Decimal 提供点而不是逗号,这是由于 .NET 处理本地化的方式(根据 this)。

这意味着 .NET 正在剥离 ,,而不是插入您预期的 8.7,而是得到 87。这也解释了为什么手动将数据直接输入数据库有效,而以编程方式输入则无效。

阅读这个问题似乎使用System.Globalization.CultureInfo.InvariantCulture 有效,但过了一段时间我能够通过将Decimal 转换为String Constant 来做到这一点:

Const price As String = "8,7"
Dim price2 As String
price2 = String.Format(price, _
price.ToString(System.Globalization.CultureInfo.InvariantCulture))
ProductsTableAdapter.Insert(id,name,price)

MSDN documentation 声明您还需要使用Imports System.GlobalizationImport Globalization 命名空间。

【讨论】:

  • 我试过了,但还是不行。我开始认为这里的问题是适配器,所以我销毁了 DataSet 并创建了一个新的,但仍然遇到同样的问题。
  • @Fernando 这对我有用,请告诉我您的系统使用的是什么语言。
  • 我的系统语言是西班牙语。如果它有帮助,在我制作这个程序之前,我使用 VB.NET 和 Mysql 并且一切正常。然后测试问题是否出在适配器上,您可以使用另一个具有十进制值的数据库创建另一个项目,并且是同样的问题。
  • 使用 MsgBox() 进行测试我发现十进制值存储为 8,7 而不是 8.7 ,更重要的是,如果您直接在数据库上键入一个值,无论您是否使用十进制数将小数点放在“,”或“.”后面。所以现在我真的迷路了。
  • @Fernando 我也很茫然,因为我为你写的代码有效,我自己测试过。
【解决方案3】:

我遇到了同样的问题,但我正在使用 C# 应用程序, 以防万一有人遇到同样的问题,我会发布对我有用的技巧...

这真的很奇怪,但我在某个论坛上找到了它,但没有解释它为什么起作用。

当传递我的 SQL 命令的参数时,我所做的只是在十进制参数上添加 ToString(),如下所示:

cmd.Parameters.AddWithValue("@DecimalParameter", model.DecimalParameter.ToString());

现在可以正确存储十进制值!

【讨论】:

    【解决方案4】:

    根据@Astopher,问题在于,.NET 期望您为 Decimal 提供点而不是逗号,这是由于如何。因此,我将命令参数的类型更改为 varchar 并且它起作用了。

    cm.Parameters.Add("@decimalcolum", OleDbType.VarChar);
    cm.Parameters["@decimalcolum"].Value=decimalvalue;
    cm.ExecuteNonQuery();
    

    它在越南语、法语(法国)、英语(美国)地区和语言上进行了测试。我希望这个问题得到解决!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-21
      • 1970-01-01
      • 2019-10-30
      相关资源
      最近更新 更多