You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VB.NET提交DataGridView更改报错及增删改存盘解决方案

DataGridView提交Access数据库更改的错误解决与完整实现

错误原因与问题解答

错误原因

抛出System.InvalidOperationException: 'Update requires a valid UpdateCommand when passed DataRow collection with modified rows.'错误的核心原因是:OleDbDataAdapter仅配置了SelectCommand用于查询数据,但未设置对应的UpdateCommand、InsertCommand、DeleteCommand来处理数据的修改、新增和删除操作。直接调用Update()方法时,适配器没有可用命令同步DataTable的更改到数据库。

关于新增/删除行的提交

只要配置正确,DataGridView中的新增、删除行更改可以同步到磁盘数据库,具体实现分为两种思路。

解决方案

方案1:使用OleDbCommandBuilder自动生成命令(简洁高效)

利用OleDbCommandBuilder基于已有的SelectCommand自动生成更新、插入、删除命令,适合单表简单操作:

' 在btnTest_Click方法中,设置ResultsAdapter.SelectCommand后添加以下代码
Dim cmdBuilder As New OleDbCommandBuilder(ResultsAdapter)
' 自动生成所需命令,无需手动编写SQL
cmdBuilder.GetUpdateCommand()
cmdBuilder.GetInsertCommand()
cmdBuilder.GetDeleteCommand()

修改后的btnSave_Click方法只需一行代码即可同步所有更改:

Private Sub btnSave_Click(sender As Object, e As EventArgs) Handles btnSave.Click
    Try
        ResultsAdapter.Update(ResultsTable)
        MsgBox("数据已保存", vbOKOnly, "操作成功")
    Catch ex As Exception
        MsgBox("保存失败:" & ex.Message, vbOKOnly, "错误")
    End Try
End Sub

注意:使用该方案要求查询的表必须有主键,否则CommandBuilder无法自动生成命令。

方案2:手动编写SQL命令处理更改(精细控制)

如果需要自定义业务逻辑或处理特殊场景,可以手动遍历DataGridView行,分别处理新增、更新、删除操作,代码实现如下:

Imports System.Data
Imports System.Data.OleDb
Imports System.Collections.Generic

Public Class Form1
    Dim BooksConnection As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0; " _
    + "Data Source = D:\My Docs\BooksDb.accdb")
    Dim ResultsCommand As OleDbCommand = Nothing
    Dim ResultsAdapter As New OleDbDataAdapter
    Dim ResultsTable As New DataTable
    Dim strTableName As String = "Authors"
    Dim lstDeletedIDs As New List(Of Long) ' 记录被删除行的AU_ID

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        BooksConnection.Open()
        txtSQLtester.Text = "SELECT * FROM " + strTableName
    End Sub

    Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
        BooksConnection.Close()
    End Sub

    Private Sub btnTest_Click(sender As Object, e As EventArgs) Handles btnTest.Click
        Try
            ResultsCommand = New OleDbCommand(txtSQLtester.Text, BooksConnection)
            ResultsAdapter.SelectCommand = ResultsCommand
            ResultsTable.Clear() ' 清空旧数据,避免重复加载
            ResultsAdapter.Fill(ResultsTable)
            grdSQLtester.DataSource = ResultsTable
            ResultsCommand.Dispose()
            lstDeletedIDs.Clear() ' 清空删除记录列表,避免重复删除
        Catch ex As Exception
            MsgBox("SQL语句执行失败", vbOKOnly, "SQL错误")
        End Try
    End Sub

    Private Sub btnSave_Click(sender As Object, e As EventArgs) Handles btnSave.Click
        Dim strCmd As String, row As Integer
        ' 处理修改和新增行
        For row = 0 To grdSQLtester.Rows.Count() - 2 ' 忽略末尾自动生成的空行
            With grdSQLtester.Rows(row).Cells
                If .Item("Au_ID").Value Is Nothing OrElse .Item("Au_ID").Value.ToString.Trim() = "" Then
                    ' 新增记录:检查必填字段是否有效
                    If Not .Item("Author").Value Is Nothing AndAlso .Item("Author").Value.ToString.Trim().Length > 0 Then
                        ' 注意:生产环境请使用参数化查询替代字符串拼接
                        strCmd = $"INSERT INTO {strTableName} (Author,Year_Born) VALUES ('{.Item("Author").Value.ToString.Trim()}',{.Item("Year_Born").Value.ToString})"
                        ExecuteSQL(strCmd)
                    End If
                Else
                    ' 更新现有记录
                    strCmd = $"UPDATE {strTableName} SET Author = '{.Item("Author").Value.ToString.Trim()}', Year_Born = {.Item("Year_Born").Value.ToString} WHERE Au_ID = {.Item("Au_ID").Value.ToString}"
                    ExecuteSQL(strCmd)
                End If
            End With
        Next row
        ' 处理删除行
        For Each ID In lstDeletedIDs
            strCmd = $"DELETE FROM {strTableName} WHERE Au_ID = {ID.ToString}"
            ExecuteSQL(strCmd)
        Next
        ' 刷新DataGridView显示最新数据
        btnTest.PerformClick()
        MsgBox("数据已保存", vbOKOnly, "操作成功")
    End Sub

    Sub ExecuteSQL(strCmd As String)
        ResultsCommand = New OleDbCommand(strCmd, BooksConnection)
        ResultsCommand.ExecuteNonQuery()
        ResultsCommand.Dispose()
    End Sub

    Private Sub grdSQLtester_UserDeletingRow(sender As Object, e As DataGridViewRowCancelEventArgs) Handles grdSQLtester.UserDeletingRow
        ' 记录要删除的行主键ID
        If Not e.Row.Cells.Item("au_ID").Value Is Nothing Then
            Dim ID As Long = CLng(e.Row.Cells.Item("au_ID").Value)
            lstDeletedIDs.Add(ID)
        End If
    End Sub
End Class

关键注意事项

  • SQL注入风险:代码中使用字符串拼接SQL仅用于学习,生产环境必须使用参数化查询,示例如下:
    ' 参数化插入示例
    strCmd = "INSERT INTO Authors (Author,Year_Born) VALUES (@Author,@Year_Born)"
    ResultsCommand = New OleDbCommand(strCmd, BooksConnection)
    ResultsCommand.Parameters.AddWithValue("@Author", .Item("Author").Value)
    ResultsCommand.Parameters.AddWithValue("@Year_Born", .Item("Year_Born").Value)
    ResultsCommand.ExecuteNonQuery()
    
  • 空值处理:必须判断字段值是否为空,避免因空值导致SQL语法错误或类型转换异常。
  • 资源释放:使用Dispose()释放OleDbCommand等资源,避免内存泄漏。

内容的提问来源于stack exchange,提问作者BitTwiddler

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 14:18:00