从 VB 2015 更新 MS Access 数据库
Updating an MS Access database from VB 2015
我正在尝试从 VB 2015 代码更新 MS Access 数据库。数据集信息未返回到数据库。
我已经阅读了这里的答案,其中说您不能在更新前接受更改,但是如果将其注释掉,那么下面的 da.Update(ds) 会给出:
An unhandled exception of type 'System.InvalidOperationException' occurred in System.Data.dll
Additional Information: Update requires a valid UpdateCommand when passed DataRow collection with modified rows.
数据库TestDb – 一个Table = 测试Table – 设计:
Name Type Size
-------- ------- ------
ID Long Integer 4 Primary Key
Name Text 255
NumberOne Long Integer 4
NumberTwo Long Integer 4
内容:
测试Table
ID Name NumberOne NumberTwo
1 EntryOne 1
2 EntryTwo 2
3 EntryThree 3
4 EntryFour 4
5 EntryFive 5
请注意,“NumberTwo”列有意留空。
计划DbTest.vb
启动时,程序将数据库加载到数据集中。 <<、<、> 和 >> 按钮可用于逐步浏览数据。
执行按钮用“NumberOne”列中条目的方块填充数据集的“NumberTwo”列。
“保存”按钮尝试通过数据适配器将修改后的数据集保存回数据库。然后将数据库加载到第二个数据集中,以检查第一个数据集是否已正确保存回数据库。然后逐步查看数据,发现保存失败。
我的代码:
'**********
' DbTest.vb
' Version 0.00
' MDJ 2015/11/11
'**********
Imports System
Imports System.IO
Imports System.Text
Public Class Form1
Dim conn As NewOleDb.OleDbConnection(connectionString:="Provider=Microsoft.ACE.OLEDB.12.0;Data Source=TestDB.accdb;Persist Security Info=False;")
Dim strSQL As String = "SELECT * FROM TestTable"
Dim da As New OleDb.OleDbDataAdapter(strSQL, conn)
Dim ds As New DataSet()
Dim ds2 As New DataSet()
Dim intCurrentIndex As Integer
Dim dSaved As Boolean = False
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
dSaved = False
txtError.Text = "No Exceptions"
Try
conn.Open()
Catch ex As OleDb.OleDbException
txtError.Text = "OleDbException"
GoTo errExit
Catch ex As DataException
txtError.Text = "DataException"
GoTo errExit
Catch ex As Exception
txtError.Text = "Other Exception"
GoTo errExit
End Try
txtError.Text = "Error: ds Is Empty"
' Fill dataset from database
da.Fill(ds)
'Check if the Table is empty
If ds.Tables(0).Rows.Count > 0 Then
txtError.Text = "No Error"
End If
errExit:
conn.Close()
End Sub
Private Sub btnFirst_Click(sender As Object, e As EventArgs) Handles btnFirst.Click
'Since 0 is the first row
intCurrentIndex = 0
txtID.Text = ds.Tables(0).Rows(intCurrentIndex).Item("ID").ToString()
txtName.Text = ds.Tables(0).Rows(intCurrentIndex).Item("Name").ToString()
txtNumberOne.Text = ds.Tables(0).Rows(intCurrentIndex).Item("NumberOne").ToString()
txtNumberTwo.Text = ds.Tables(0).Rows(intCurrentIndex).Item("NumberTwo").ToString()
If dSaved = True Then
txtDaNumberTwo.Text = ds2.Tables(0).Rows(intCurrentIndex).Item("NumberTwo").ToString()
End If
End Sub
Private Sub btnPrevious_Click(sender As Object, e As EventArgs) Handles btnPrevious.Click
'We move back only if we're not at the first row.
If intCurrentIndex > 0 Then
'Subtract one from the current index.
intCurrentIndex = intCurrentIndex - 1
txtID.Text = ds.Tables(0).Rows(intCurrentIndex).Item("ID").ToString()
txtName.Text = ds.Tables(0).Rows(intCurrentIndex).Item("Name").ToString()
txtNumberOne.Text = ds.Tables(0).Rows(intCurrentIndex).Item("NumberOne").ToString()
txtNumberTwo.Text = ds.Tables(0).Rows(intCurrentIndex).Item("NumberTwo").ToString()
If dSaved = True Then
txtDaNumberTwo.Text = ds2.Tables(0).Rows(intCurrentIndex).Item("NumberTwo").ToString()
End If
Else
MessageBox.Show("You're already at the first record.")
End If
End Sub
Private Sub btnNext_Click(sender As Object, e As EventArgs) Handles btnNext.Click
'ds.Tables(0).Rows.Count - 1 is the index for the last row
'We move forward only if we're not at the last row.
If intCurrentIndex < ds.Tables(0).Rows.Count - 1 Then
'Add one to the current index.
intCurrentIndex = intCurrentIndex + 1
txtID.Text = ds.Tables(0).Rows(intCurrentIndex).Item("ID").ToString()
txtName.Text = ds.Tables(0).Rows(intCurrentIndex).Item("Name").ToString()
txtNumberOne.Text = ds.Tables(0).Rows(intCurrentIndex).Item("NumberOne").ToString()
txtNumberTwo.Text = ds.Tables(0).Rows(intCurrentIndex).Item("NumberTwo").ToString()
If dSaved = True Then
txtDaNumberTwo.Text = ds2.Tables(0).Rows(intCurrentIndex).Item("NumberTwo").ToString()
End If
Else
MessageBox.Show("You're already at the last record.")
End If
End Sub
Private Sub btnLast_Click(sender As Object, e As EventArgs) Handles btnLast.Click
'ds.Tables(0).Rows.Count - 1 is the index for the last row
intCurrentIndex = ds.Tables(0).Rows.Count - 1
txtID.Text = ds.Tables(0).Rows(intCurrentIndex).Item("ID").ToString()
txtName.Text = ds.Tables(0).Rows(intCurrentIndex).Item("Name").ToString()
txtNumberOne.Text = ds.Tables(0).Rows(intCurrentIndex).Item("NumberOne").ToString()
txtNumberTwo.Text = ds.Tables(0).Rows(intCurrentIndex).Item("NumberTwo").ToString()
If dSaved = True Then
txtDaNumberTwo.Text = ds2.Tables(0).Rows(intCurrentIndex).Item("NumberTwo").ToString()
End If
End Sub
Private Sub btnExecute_Click(sender As Object, e As EventArgs) Handles btnExecute.Click
Dim n1 As Integer
Dim n2 As Integer
'ds.Tables(0).Rows.Count - 1 is the index for the last row
Dim intLastCount As Integer
intLastCount = ds.Tables(0).Rows.Count - 1
' Process each record
For intCurrentIndex = 0 To intLastCount
n1 = ds.Tables(0).Rows(intCurrentIndex).Item("NumberOne")
n2 = n1 * n1
ds.Tables(0).Rows(intCurrentIndex).Item("NumberTwo") = n2
Next
' If this is commented out, then da.Update(ds) below gives:
' An unhandled exception of type 'System.InvalidOperationException' occurred in System.Data.dll
' Additional Information: Update requires a valid UpdateCommand when passed DataRow collection with modified rows.
ds.AcceptChanges()
End Sub
Private Sub btnSave_Click(sender As Object, e As EventArgs) Handles btnSave.Click
txtError.Text = "No Exceptions"
Try
conn.Open()
Catch ex As OleDb.OleDbException
txtError.Text = "OleDbException"
GoTo errExit
Catch ex As DataException
txtError.Text = "DataException"
GoTo errExit
Catch ex As Exception
txtError.Text = "Other Exception"
GoTo errExit
End Try
ERRLOC:
' THE PROBLEM IS HERE
' The dataset is not being updated back to the data adapter
' Save dataset to database
da.Update(ds)
ENDERR:
' Fill second dataset from database
txtError.Text = "Error: ds2 Is Empty"
da.Fill(ds2)
'Check if the Table is empty
If ds2.Tables(0).Rows.Count > 0 Then
dSaved = True
txtError.Text = "ds2: No Error"
End If
errExit:
conn.Close()
End Sub
End Class
我在这里错过了什么?
Update requires a valid UpdateCommand when passed DataRow collection with modified rows.
错误消息告诉您 OleDbDataAdapter 没有为其定义 UpdateCommand。定义 InsertCommand、UpdateCommand 和 DeleteCommand 属性的最常见方法可能是使用 OleDbCommandBuilder 对象。例如
Dim da As New OleDb.OleDbDataAdapter(strSQL, conn)
Dim cb As New OleDbCommandBuilder(da)
cb.QuotePrefix = "["
cb.QuoteSuffix = "]"
对于那些可能遇到类似问题的人,下面发布了正确且有效的代码。
数据库 TestDb 位于本地 \bin\Debug 文件夹中。
Form1 是主要且唯一的表格。
Form1 的设备包括:
Five Label – TextBox combinations, arranged in a vertical column
Label1 Text = “ID” – TextBox Name = “txtID”
Label2 Text = “Name” – TextBox Name = “txtName”
Label3 Text = “NumberOne” – TextBox Name = “txtNumberOne”
Label4 Text = “NumberTwo” – TextBox Name = “txtNumberTwo”
Label5 Text = “da’s NumberTwo” – TextBox Name = “txtDaNumberTwo”
(Label4 – TextBox refers to the value in the DataSet)
(Label5 – TextBox refers to the value in the database)
Four buttons, side-by-side
btnFirst – Text = “<<”
btnPrevious – Text = “<”
btnNext – Text = “>”
btnLast – Text = “>>”
Two buttons, one above the other
btnExecute – Text = “Execute”
btnSave – Text = “Save”
One Label – TextBox combination
Label6 Text = “Error” – TextBox Name = “txtError”
正确的工作代码:
'**********
' DbTest.vb
' Version 0.00
' MDJ 2015/11/11
'**********
Imports System
Imports System.IO
Imports System.Text
Imports System.Data
Imports System.Data.OleDb
Public Class Form1
' This is the connection to the local MS Access database.
' The database is needed in both the Debug and Release folders.
Dim conn As New OleDb.OleDbConnection(connectionString:="Provider=Microsoft.ACE.OLEDB.12.0;Data Source=TestDB.accdb;Persist Security Info=False;")
Dim strSQL As String = "SELECT * FROM TestTable"
' The DataAdapter is the bridge between the database and the DataSet.
Dim da As New OleDb.OleDbDataAdapter(strSQL, conn)
' MUST INCLUDE:
' OleDbCommandBuilder statement is required for Insert, Update, and Delete
' as are the cb.Quote... statements below.
Dim cb As New OleDbCommandBuilder(da)
' The DataSet is the internal working copy of the portion of the database which is being processed.
' More than one dataset may be open at any given time.
Dim ds As New DataSet()
Dim ds2 As New DataSet()
Dim intCurrentIndex As Integer
Dim dSaved As Boolean = False
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
cb.QuotePrefix = "["
cb.QuoteSuffix = "]"
dSaved = False
txtError.Text = "No Exceptions"
Try
conn.Open()
Catch ex As OleDb.OleDbException
txtError.Text = "OleDbException"
GoTo errExit
Catch ex As DataException
txtError.Text = "DataException"
GoTo errExit
Catch ex As Exception
txtError.Text = "Other Exception"
GoTo errExit
End Try
txtError.Text = "Error: ds Is Empty"
' Fill dataset from database
da.Fill(ds)
'Check if the Table is empty
If ds.Tables(0).Rows.Count > 0 Then
txtError.Text = "No Error"
End If
errExit:
conn.Close()
End Sub
Private Sub btnFirst_Click(sender As Object, e As EventArgs) Handles btnFirst.Click
'Since 0 is the first row
intCurrentIndex = 0
txtID.Text = ds.Tables(0).Rows(intCurrentIndex).Item("ID").ToString()
txtName.Text = ds.Tables(0).Rows(intCurrentIndex).Item("Name").ToString()
txtNumberOne.Text = ds.Tables(0).Rows(intCurrentIndex).Item("NumberOne").ToString()
txtNumberTwo.Text = ds.Tables(0).Rows(intCurrentIndex).Item("NumberTwo").ToString()
If dSaved = True Then
txtDaNumberTwo.Text = ds2.Tables(0).Rows(intCurrentIndex).Item("NumberTwo").ToString()
End If
End Sub
Private Sub btnPrevious_Click(sender As Object, e As EventArgs) Handles btnPrevious.Click
'We move back only if we're not at the first row.
If intCurrentIndex > 0 Then
'Subtract one from the current index.
intCurrentIndex = intCurrentIndex - 1
txtID.Text = ds.Tables(0).Rows(intCurrentIndex).Item("ID").ToString()
txtName.Text = ds.Tables(0).Rows(intCurrentIndex).Item("Name").ToString()
txtNumberOne.Text = ds.Tables(0).Rows(intCurrentIndex).Item("NumberOne").ToString()
txtNumberTwo.Text = ds.Tables(0).Rows(intCurrentIndex).Item("NumberTwo").ToString()
If dSaved = True Then
txtDaNumberTwo.Text = ds2.Tables(0).Rows(intCurrentIndex).Item("NumberTwo").ToString()
End If
Else
MessageBox.Show("You're already at the first record.")
End If
End Sub
Private Sub btnNext_Click(sender As Object, e As EventArgs) Handles btnNext.Click
'ds.Tables(0).Rows.Count - 1 is the index for the last row
'We move forward only if we're not at the last row.
If intCurrentIndex < ds.Tables(0).Rows.Count - 1 Then
'Add one to the current index.
intCurrentIndex = intCurrentIndex + 1
txtID.Text = ds.Tables(0).Rows(intCurrentIndex).Item("ID").ToString()
txtName.Text = ds.Tables(0).Rows(intCurrentIndex).Item("Name").ToString()
txtNumberOne.Text = ds.Tables(0).Rows(intCurrentIndex).Item("NumberOne").ToString()
txtNumberTwo.Text = ds.Tables(0).Rows(intCurrentIndex).Item("NumberTwo").ToString()
If dSaved = True Then
txtDaNumberTwo.Text = ds2.Tables(0).Rows(intCurrentIndex).Item("NumberTwo").ToString()
End If
Else
MessageBox.Show("You're already at the last record.")
End If
End Sub
Private Sub btnLast_Click(sender As Object, e As EventArgs) Handles btnLast.Click
'ds.Tables(0).Rows.Count - 1 is the index for the last row
intCurrentIndex = ds.Tables(0).Rows.Count - 1
txtID.Text = ds.Tables(0).Rows(intCurrentIndex).Item("ID").ToString()
txtName.Text = ds.Tables(0).Rows(intCurrentIndex).Item("Name").ToString()
txtNumberOne.Text = ds.Tables(0).Rows(intCurrentIndex).Item("NumberOne").ToString()
txtNumberTwo.Text = ds.Tables(0).Rows(intCurrentIndex).Item("NumberTwo").ToString()
If dSaved = True Then
txtDaNumberTwo.Text = ds2.Tables(0).Rows(intCurrentIndex).Item("NumberTwo").ToString()
End If
End Sub
Private Sub btnExecute_Click(sender As Object, e As EventArgs) Handles btnExecute.Click
Dim n1 As Integer
Dim n2 As Integer
'ds.Tables(0).Rows.Count - 1 is the index for the last row
Dim intLastCount As Integer
intLastCount = ds.Tables(0).Rows.Count - 1
' Process each record
For intCurrentIndex = 0 To intLastCount
n1 = ds.Tables(0).Rows(intCurrentIndex).Item("NumberOne")
n2 = n1 * n1
ds.Tables(0).Rows(intCurrentIndex).Item("NumberTwo") = n2
Next
' MUST NOT DO THIS BEFORE UPDATING - IT LOSES ALL CHANGES
'ds.AcceptChanges()
End Sub
Private Sub btnSave_Click(sender As Object, e As EventArgs) Handles btnSave.Click
txtError.Text = "No Exceptions"
Try
conn.Open()
Catch ex As OleDb.OleDbException
txtError.Text = "OleDbException"
GoTo errExit
Catch ex As DataException
txtError.Text = "DataException"
GoTo errExit
Catch ex As Exception
txtError.Text = "Other Exception"
GoTo errExit
End Try
' Save dataset to database
Try
da.Update(ds)
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
' Fill second dataset from database
txtError.Text = "Error: ds2 Is Empty"
da.Fill(ds2)
'Check if the Table is empty
If ds2.Tables(0).Rows.Count > 0 Then
dSaved = True
txtError.Text = "ds2: No Error"
End If
errExit:
conn.Close()
End Sub
End Class
我今天发现它实际上可能没有更新您认为应该更新的数据库。如果您在编程时是 运行 来自 Visual Studio 的程序,请查看它粘贴 executable 的 bin 文件夹并查看它放置在那里的 db 文件。
微软关于更新的说明工作得很好:
Miscrosoft Instructions
如果您进入每个 table.
的 DataSet TableAdapter 配置,VS 还可以为数据库自动生成 INSERT、DELETE 和 UPDATE 命令。
您必须为要使用 UPDATE 或 DELETE 的每个 table 设置一个主键。
我正在尝试从 VB 2015 代码更新 MS Access 数据库。数据集信息未返回到数据库。
我已经阅读了这里的答案,其中说您不能在更新前接受更改,但是如果将其注释掉,那么下面的 da.Update(ds) 会给出:
An unhandled exception of type 'System.InvalidOperationException' occurred in System.Data.dll
Additional Information: Update requires a valid UpdateCommand when passed DataRow collection with modified rows.
数据库TestDb – 一个Table = 测试Table – 设计:
Name Type Size
-------- ------- ------
ID Long Integer 4 Primary Key
Name Text 255
NumberOne Long Integer 4
NumberTwo Long Integer 4
内容:
测试Table
ID Name NumberOne NumberTwo
1 EntryOne 1
2 EntryTwo 2
3 EntryThree 3
4 EntryFour 4
5 EntryFive 5
请注意,“NumberTwo”列有意留空。
计划DbTest.vb
启动时,程序将数据库加载到数据集中。 <<、<、> 和 >> 按钮可用于逐步浏览数据。
执行按钮用“NumberOne”列中条目的方块填充数据集的“NumberTwo”列。
“保存”按钮尝试通过数据适配器将修改后的数据集保存回数据库。然后将数据库加载到第二个数据集中,以检查第一个数据集是否已正确保存回数据库。然后逐步查看数据,发现保存失败。
我的代码:
'**********
' DbTest.vb
' Version 0.00
' MDJ 2015/11/11
'**********
Imports System
Imports System.IO
Imports System.Text
Public Class Form1
Dim conn As NewOleDb.OleDbConnection(connectionString:="Provider=Microsoft.ACE.OLEDB.12.0;Data Source=TestDB.accdb;Persist Security Info=False;")
Dim strSQL As String = "SELECT * FROM TestTable"
Dim da As New OleDb.OleDbDataAdapter(strSQL, conn)
Dim ds As New DataSet()
Dim ds2 As New DataSet()
Dim intCurrentIndex As Integer
Dim dSaved As Boolean = False
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
dSaved = False
txtError.Text = "No Exceptions"
Try
conn.Open()
Catch ex As OleDb.OleDbException
txtError.Text = "OleDbException"
GoTo errExit
Catch ex As DataException
txtError.Text = "DataException"
GoTo errExit
Catch ex As Exception
txtError.Text = "Other Exception"
GoTo errExit
End Try
txtError.Text = "Error: ds Is Empty"
' Fill dataset from database
da.Fill(ds)
'Check if the Table is empty
If ds.Tables(0).Rows.Count > 0 Then
txtError.Text = "No Error"
End If
errExit:
conn.Close()
End Sub
Private Sub btnFirst_Click(sender As Object, e As EventArgs) Handles btnFirst.Click
'Since 0 is the first row
intCurrentIndex = 0
txtID.Text = ds.Tables(0).Rows(intCurrentIndex).Item("ID").ToString()
txtName.Text = ds.Tables(0).Rows(intCurrentIndex).Item("Name").ToString()
txtNumberOne.Text = ds.Tables(0).Rows(intCurrentIndex).Item("NumberOne").ToString()
txtNumberTwo.Text = ds.Tables(0).Rows(intCurrentIndex).Item("NumberTwo").ToString()
If dSaved = True Then
txtDaNumberTwo.Text = ds2.Tables(0).Rows(intCurrentIndex).Item("NumberTwo").ToString()
End If
End Sub
Private Sub btnPrevious_Click(sender As Object, e As EventArgs) Handles btnPrevious.Click
'We move back only if we're not at the first row.
If intCurrentIndex > 0 Then
'Subtract one from the current index.
intCurrentIndex = intCurrentIndex - 1
txtID.Text = ds.Tables(0).Rows(intCurrentIndex).Item("ID").ToString()
txtName.Text = ds.Tables(0).Rows(intCurrentIndex).Item("Name").ToString()
txtNumberOne.Text = ds.Tables(0).Rows(intCurrentIndex).Item("NumberOne").ToString()
txtNumberTwo.Text = ds.Tables(0).Rows(intCurrentIndex).Item("NumberTwo").ToString()
If dSaved = True Then
txtDaNumberTwo.Text = ds2.Tables(0).Rows(intCurrentIndex).Item("NumberTwo").ToString()
End If
Else
MessageBox.Show("You're already at the first record.")
End If
End Sub
Private Sub btnNext_Click(sender As Object, e As EventArgs) Handles btnNext.Click
'ds.Tables(0).Rows.Count - 1 is the index for the last row
'We move forward only if we're not at the last row.
If intCurrentIndex < ds.Tables(0).Rows.Count - 1 Then
'Add one to the current index.
intCurrentIndex = intCurrentIndex + 1
txtID.Text = ds.Tables(0).Rows(intCurrentIndex).Item("ID").ToString()
txtName.Text = ds.Tables(0).Rows(intCurrentIndex).Item("Name").ToString()
txtNumberOne.Text = ds.Tables(0).Rows(intCurrentIndex).Item("NumberOne").ToString()
txtNumberTwo.Text = ds.Tables(0).Rows(intCurrentIndex).Item("NumberTwo").ToString()
If dSaved = True Then
txtDaNumberTwo.Text = ds2.Tables(0).Rows(intCurrentIndex).Item("NumberTwo").ToString()
End If
Else
MessageBox.Show("You're already at the last record.")
End If
End Sub
Private Sub btnLast_Click(sender As Object, e As EventArgs) Handles btnLast.Click
'ds.Tables(0).Rows.Count - 1 is the index for the last row
intCurrentIndex = ds.Tables(0).Rows.Count - 1
txtID.Text = ds.Tables(0).Rows(intCurrentIndex).Item("ID").ToString()
txtName.Text = ds.Tables(0).Rows(intCurrentIndex).Item("Name").ToString()
txtNumberOne.Text = ds.Tables(0).Rows(intCurrentIndex).Item("NumberOne").ToString()
txtNumberTwo.Text = ds.Tables(0).Rows(intCurrentIndex).Item("NumberTwo").ToString()
If dSaved = True Then
txtDaNumberTwo.Text = ds2.Tables(0).Rows(intCurrentIndex).Item("NumberTwo").ToString()
End If
End Sub
Private Sub btnExecute_Click(sender As Object, e As EventArgs) Handles btnExecute.Click
Dim n1 As Integer
Dim n2 As Integer
'ds.Tables(0).Rows.Count - 1 is the index for the last row
Dim intLastCount As Integer
intLastCount = ds.Tables(0).Rows.Count - 1
' Process each record
For intCurrentIndex = 0 To intLastCount
n1 = ds.Tables(0).Rows(intCurrentIndex).Item("NumberOne")
n2 = n1 * n1
ds.Tables(0).Rows(intCurrentIndex).Item("NumberTwo") = n2
Next
' If this is commented out, then da.Update(ds) below gives:
' An unhandled exception of type 'System.InvalidOperationException' occurred in System.Data.dll
' Additional Information: Update requires a valid UpdateCommand when passed DataRow collection with modified rows.
ds.AcceptChanges()
End Sub
Private Sub btnSave_Click(sender As Object, e As EventArgs) Handles btnSave.Click
txtError.Text = "No Exceptions"
Try
conn.Open()
Catch ex As OleDb.OleDbException
txtError.Text = "OleDbException"
GoTo errExit
Catch ex As DataException
txtError.Text = "DataException"
GoTo errExit
Catch ex As Exception
txtError.Text = "Other Exception"
GoTo errExit
End Try
ERRLOC:
' THE PROBLEM IS HERE
' The dataset is not being updated back to the data adapter
' Save dataset to database
da.Update(ds)
ENDERR:
' Fill second dataset from database
txtError.Text = "Error: ds2 Is Empty"
da.Fill(ds2)
'Check if the Table is empty
If ds2.Tables(0).Rows.Count > 0 Then
dSaved = True
txtError.Text = "ds2: No Error"
End If
errExit:
conn.Close()
End Sub
End Class
我在这里错过了什么?
Update requires a valid UpdateCommand when passed DataRow collection with modified rows.
错误消息告诉您 OleDbDataAdapter 没有为其定义 UpdateCommand。定义 InsertCommand、UpdateCommand 和 DeleteCommand 属性的最常见方法可能是使用 OleDbCommandBuilder 对象。例如
Dim da As New OleDb.OleDbDataAdapter(strSQL, conn)
Dim cb As New OleDbCommandBuilder(da)
cb.QuotePrefix = "["
cb.QuoteSuffix = "]"
对于那些可能遇到类似问题的人,下面发布了正确且有效的代码。
数据库 TestDb 位于本地 \bin\Debug 文件夹中。
Form1 是主要且唯一的表格。
Form1 的设备包括:
Five Label – TextBox combinations, arranged in a vertical column
Label1 Text = “ID” – TextBox Name = “txtID”
Label2 Text = “Name” – TextBox Name = “txtName”
Label3 Text = “NumberOne” – TextBox Name = “txtNumberOne”
Label4 Text = “NumberTwo” – TextBox Name = “txtNumberTwo”
Label5 Text = “da’s NumberTwo” – TextBox Name = “txtDaNumberTwo”
(Label4 – TextBox refers to the value in the DataSet)
(Label5 – TextBox refers to the value in the database)
Four buttons, side-by-side
btnFirst – Text = “<<”
btnPrevious – Text = “<”
btnNext – Text = “>”
btnLast – Text = “>>”
Two buttons, one above the other
btnExecute – Text = “Execute”
btnSave – Text = “Save”
One Label – TextBox combination
Label6 Text = “Error” – TextBox Name = “txtError”
正确的工作代码:
'**********
' DbTest.vb
' Version 0.00
' MDJ 2015/11/11
'**********
Imports System
Imports System.IO
Imports System.Text
Imports System.Data
Imports System.Data.OleDb
Public Class Form1
' This is the connection to the local MS Access database.
' The database is needed in both the Debug and Release folders.
Dim conn As New OleDb.OleDbConnection(connectionString:="Provider=Microsoft.ACE.OLEDB.12.0;Data Source=TestDB.accdb;Persist Security Info=False;")
Dim strSQL As String = "SELECT * FROM TestTable"
' The DataAdapter is the bridge between the database and the DataSet.
Dim da As New OleDb.OleDbDataAdapter(strSQL, conn)
' MUST INCLUDE:
' OleDbCommandBuilder statement is required for Insert, Update, and Delete
' as are the cb.Quote... statements below.
Dim cb As New OleDbCommandBuilder(da)
' The DataSet is the internal working copy of the portion of the database which is being processed.
' More than one dataset may be open at any given time.
Dim ds As New DataSet()
Dim ds2 As New DataSet()
Dim intCurrentIndex As Integer
Dim dSaved As Boolean = False
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
cb.QuotePrefix = "["
cb.QuoteSuffix = "]"
dSaved = False
txtError.Text = "No Exceptions"
Try
conn.Open()
Catch ex As OleDb.OleDbException
txtError.Text = "OleDbException"
GoTo errExit
Catch ex As DataException
txtError.Text = "DataException"
GoTo errExit
Catch ex As Exception
txtError.Text = "Other Exception"
GoTo errExit
End Try
txtError.Text = "Error: ds Is Empty"
' Fill dataset from database
da.Fill(ds)
'Check if the Table is empty
If ds.Tables(0).Rows.Count > 0 Then
txtError.Text = "No Error"
End If
errExit:
conn.Close()
End Sub
Private Sub btnFirst_Click(sender As Object, e As EventArgs) Handles btnFirst.Click
'Since 0 is the first row
intCurrentIndex = 0
txtID.Text = ds.Tables(0).Rows(intCurrentIndex).Item("ID").ToString()
txtName.Text = ds.Tables(0).Rows(intCurrentIndex).Item("Name").ToString()
txtNumberOne.Text = ds.Tables(0).Rows(intCurrentIndex).Item("NumberOne").ToString()
txtNumberTwo.Text = ds.Tables(0).Rows(intCurrentIndex).Item("NumberTwo").ToString()
If dSaved = True Then
txtDaNumberTwo.Text = ds2.Tables(0).Rows(intCurrentIndex).Item("NumberTwo").ToString()
End If
End Sub
Private Sub btnPrevious_Click(sender As Object, e As EventArgs) Handles btnPrevious.Click
'We move back only if we're not at the first row.
If intCurrentIndex > 0 Then
'Subtract one from the current index.
intCurrentIndex = intCurrentIndex - 1
txtID.Text = ds.Tables(0).Rows(intCurrentIndex).Item("ID").ToString()
txtName.Text = ds.Tables(0).Rows(intCurrentIndex).Item("Name").ToString()
txtNumberOne.Text = ds.Tables(0).Rows(intCurrentIndex).Item("NumberOne").ToString()
txtNumberTwo.Text = ds.Tables(0).Rows(intCurrentIndex).Item("NumberTwo").ToString()
If dSaved = True Then
txtDaNumberTwo.Text = ds2.Tables(0).Rows(intCurrentIndex).Item("NumberTwo").ToString()
End If
Else
MessageBox.Show("You're already at the first record.")
End If
End Sub
Private Sub btnNext_Click(sender As Object, e As EventArgs) Handles btnNext.Click
'ds.Tables(0).Rows.Count - 1 is the index for the last row
'We move forward only if we're not at the last row.
If intCurrentIndex < ds.Tables(0).Rows.Count - 1 Then
'Add one to the current index.
intCurrentIndex = intCurrentIndex + 1
txtID.Text = ds.Tables(0).Rows(intCurrentIndex).Item("ID").ToString()
txtName.Text = ds.Tables(0).Rows(intCurrentIndex).Item("Name").ToString()
txtNumberOne.Text = ds.Tables(0).Rows(intCurrentIndex).Item("NumberOne").ToString()
txtNumberTwo.Text = ds.Tables(0).Rows(intCurrentIndex).Item("NumberTwo").ToString()
If dSaved = True Then
txtDaNumberTwo.Text = ds2.Tables(0).Rows(intCurrentIndex).Item("NumberTwo").ToString()
End If
Else
MessageBox.Show("You're already at the last record.")
End If
End Sub
Private Sub btnLast_Click(sender As Object, e As EventArgs) Handles btnLast.Click
'ds.Tables(0).Rows.Count - 1 is the index for the last row
intCurrentIndex = ds.Tables(0).Rows.Count - 1
txtID.Text = ds.Tables(0).Rows(intCurrentIndex).Item("ID").ToString()
txtName.Text = ds.Tables(0).Rows(intCurrentIndex).Item("Name").ToString()
txtNumberOne.Text = ds.Tables(0).Rows(intCurrentIndex).Item("NumberOne").ToString()
txtNumberTwo.Text = ds.Tables(0).Rows(intCurrentIndex).Item("NumberTwo").ToString()
If dSaved = True Then
txtDaNumberTwo.Text = ds2.Tables(0).Rows(intCurrentIndex).Item("NumberTwo").ToString()
End If
End Sub
Private Sub btnExecute_Click(sender As Object, e As EventArgs) Handles btnExecute.Click
Dim n1 As Integer
Dim n2 As Integer
'ds.Tables(0).Rows.Count - 1 is the index for the last row
Dim intLastCount As Integer
intLastCount = ds.Tables(0).Rows.Count - 1
' Process each record
For intCurrentIndex = 0 To intLastCount
n1 = ds.Tables(0).Rows(intCurrentIndex).Item("NumberOne")
n2 = n1 * n1
ds.Tables(0).Rows(intCurrentIndex).Item("NumberTwo") = n2
Next
' MUST NOT DO THIS BEFORE UPDATING - IT LOSES ALL CHANGES
'ds.AcceptChanges()
End Sub
Private Sub btnSave_Click(sender As Object, e As EventArgs) Handles btnSave.Click
txtError.Text = "No Exceptions"
Try
conn.Open()
Catch ex As OleDb.OleDbException
txtError.Text = "OleDbException"
GoTo errExit
Catch ex As DataException
txtError.Text = "DataException"
GoTo errExit
Catch ex As Exception
txtError.Text = "Other Exception"
GoTo errExit
End Try
' Save dataset to database
Try
da.Update(ds)
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
' Fill second dataset from database
txtError.Text = "Error: ds2 Is Empty"
da.Fill(ds2)
'Check if the Table is empty
If ds2.Tables(0).Rows.Count > 0 Then
dSaved = True
txtError.Text = "ds2: No Error"
End If
errExit:
conn.Close()
End Sub
End Class
我今天发现它实际上可能没有更新您认为应该更新的数据库。如果您在编程时是 运行 来自 Visual Studio 的程序,请查看它粘贴 executable 的 bin 文件夹并查看它放置在那里的 db 文件。
微软关于更新的说明工作得很好: Miscrosoft Instructions
如果您进入每个 table.
的 DataSet TableAdapter 配置,VS 还可以为数据库自动生成 INSERT、DELETE 和 UPDATE 命令。您必须为要使用 UPDATE 或 DELETE 的每个 table 设置一个主键。