Access 数据库不能正确保存十进制值

Access database doesn't save decimal values correctly

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

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

table中的字段为小数,小数位数 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,它也一样,它可以很好地处理这两个值,所以现在我不知道为什么这样做工作。

问题似乎是 .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 声明您还需要 Import Globalization 命名空间使用 Imports System.Globalization

我已经能够重现问题。在 Windows 系统区域设置不使用句点字符 (.) 作为小数点符号的机器上运行时,它似乎是 Access OLEDB 提供程序的 "unfortunate feature"。

使用以下代码

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 设置为 "English (United States)" 我看到调试输出

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

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

将 Windows 设置为 "Spanish (Spain)" 相同的代码现在生成

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

但值 87 仍被插入。

将 Windows 设置为 "French (Canada)" 调试输出相同

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

然而,插入失败 "Data type mismatch in criteria expression."

通过替换

获得了完全相同的结果
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 似乎已经解决了 "Spanish (Spain)" 和 "French (Canada)" 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。

我遇到了同样的问题,但我正在处理 C# 应用程序, 以防万一有人遇到同样的问题我会 post 是什么对我有用...

这真的很奇怪,但我在某个论坛上发现了它,但没有解释它为什么有效。

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

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

十进制值现在已正确存储!

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

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

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