在 MS Access 中保存来自 VB.Net Windows 窗体的数据时出现错误 System.Data.OleDb.OleDbException:“标准表达式中的数据类型不匹配”。

Posted

技术标签:

【中文标题】在 MS Access 中保存来自 VB.Net Windows 窗体的数据时出现错误 System.Data.OleDb.OleDbException:“标准表达式中的数据类型不匹配”。【英文标题】:Saving Data from VB.Net Windows Forms in MS Access having error System.Data.OleDb.OleDbException: 'Data type mismatch in criteria expression.' 【发布时间】:2021-06-13 09:44:43 【问题描述】:
str = "INSERT INTO Rent_Transaction ([Username], [Type], [Plate No], [Start Date], [End Date], [Total]) 
      VALUES('" & UsernameLog.Text & "','" & LabelType.Text & "','" & Plate.Text & "','" & StartDate.Text & "','" & EndDate.Text & "','" & Total.Text & "')"
con.Open()
cmd = New OleDbCommand(str, con)
cmd.ExecuteNonQuery()

'represents sql and db connection that are used to fill the data set and update the data source
da = New OleDbDataAdapter(cmd)

'to check if there are any matches in the table 
da.Fill(ds, "Rent_Transaction")

con.Close()
con.Dispose()

错误在 cmd.ExecuteNonQuery 中。我无法将数据保存在 ms 访问中

【问题讨论】:

不要使用字符串连接来构建 SQL 语句。正确执行并使用参数,这个问题就会消失,还有其他几个问题。阅读更多here。 查看所有传递给数据库引擎的值,就像接收字段是字符串类型一样。显然他们不是。这是构建 sql 代码时使用参数的众多原因之一。当然最糟糕的问题是 Sql Injection 问题 代码中的另一个错误是对 SqlDataAdapter.Fill 的调用。当您想从数据库中 读取 时应该使用该调用(命令中有一个选择查询),而不是在您想要插入/更新或删除时使用。尽管如此,Fill 调用仍然执行传递的命令,这将导致插入双记录(第一个由 ExecuteNonQuery,第二个由 Fill) 快速解决方法是对日期/时间字段使用 # 分隔符,对文本字段使用撇号,对数字字段不使用任何内容。 快速修复,可能与当前查询一样危险。 【参考方案1】:

这里我将如何执行将记录插入表中的任务:

Using con As OleDbConnection = New OleDbConnection(......)
    Dim str = "INSERT INTO Rent_Transaction ([Username], [Type], [Plate No], [Start Date], [End Date], [Total]) 
               VALUES(@name,@type,@plate, @init,@end,@total)"
    con.Open()
    Dim cmd As OleDbCommand = New OleDbCommand(str, con)
    cmd.Parameters.Add("@name", OleDbType.VarWChar).Value = UsernameLog.Text
    cmd.Parameters.Add("@type", OleDbType.VarWChar).Value = LabelType.Text
    cmd.Parameters.Add("@plate", OleDbType.VarWChar).Value = Plate.Text
    cmd.Parameters.Add("@init", OleDbType.Date).Value = Convert.ToDateTime(StartDate.Text)
    cmd.Parameters.Add("@end", OleDbType.Date).Value = Convert.ToDateTime(EndDate.Text)
    cmd.Parameters.Add("@total", OleDbType.Integer).Value = Convert.ToInt32(Total.Text)
    cmd.ExecuteNonQuery()
End Using

第一个更改是围绕创建 OleDbConnection 的 Using 语句。这将确保在代码退出 End Using 时正确关闭/处理连接。即使使用基于本地文件的数据库(如 MS-Access),这样做始终是最好的做法。

第二个变化是查询文本,现在我们有了一个包含参数占位符的字符串。没有更多的连接,没有更多的引用变量,更易于阅读和理解构造。

第三个变化是参数的构建。如您所见,每个参数都定义了一个类型,该类型应与数据库表字段所期望的类型相匹配。 注意最后三个参数的值如何转换为数据表预期的假定类型。这样,我们不允许数据库自行执行转换,这可能会导致“类型不匹配”。

最后,所有与 OleDbDataAdapter 相关的代码都被删除了。

【讨论】:

什么是 Convert.ToInt32?我尝试了代码,但出现此错误“无法将参数值从 Int32 转换为 DateTime。”。我很困惑,因为您用 Total 声明了 Convert.ToInt32 但错误将 Int32 显示为 DateTime 哦,等等,我想是因为类型 啊,对不起,需要更改参数类型(复制/粘贴经典) 另外,请记住那些 Convert.ToXXXX 是将 用户输入 从字符串转换为特定类型的非常基本的方法。如果输入值不是他们期望的格式,他们可以引发异常。特别是 DateTime 在这个意义上是非常脆弱的。如果出现问题,最好使用 DateTime.TryParseExact 进行转换并向您的用户发送错误消息。 这意味着这个表和其他一些表之间存在关系。某个字段链接到另一个表,如果另一个表没有该字段的匹配值,则不能在此处插入值

以上是关于在 MS Access 中保存来自 VB.Net Windows 窗体的数据时出现错误 System.Data.OleDb.OleDbException:“标准表达式中的数据类型不匹配”。的主要内容,如果未能解决你的问题,请参考以下文章

使用 asp.net、vb.net 和 ms-access 的时间戳

ASP.NET - VB.NET - 从 MS-Access 数据库中检索记录

ASP.NET - VB.NET - 更新 MS_Access 表

寻求代码设计建议:使用 VB.Net 和 Ms-Access

如何在 VB.net 中使用 ROWNUM 从 MS-Access 数据库中检索数据

如何使用 vb.net 从 MS Access DB 表单中找出 Activex 控件