我刚开始用vb.net自学数据库访问,我一直在使用this as a reference。我的MS Access数据库比我设置关系数据库时引用的示例稍微复杂一点。我有两张桌子;球员和村庄。每个玩家可以再拥有一个村庄(1对多关系),这种关系在玩家ID之间绑定,玩家ID是玩家表中的唯一键,在村庄表中用于定义村庄的所有者。以下是我向数据库中添加新玩家的方法;
Public Sub NewPlayer(ByVal playerName As String)
Dim playerID As Integer = getLastIdent("Players") + 1
Dim tmpnum As Integer = playerID
Dim dsNewRow As DataRow
Dim Sql As String
Sql = "SELECT * FROM Players"
da = New OleDb.OleDbDataAdapter(Sql, con)
da.Fill(ds, "Players")
Dim cb As New OleDb.OleDbCommandBuilder(da)
dsNewRow = ds.Tables("Players").NewRow()
dsNewRow.Item("ID") = playerID
dsNewRow.Item("NameP") = playerName
dsNewRow.Item("Coins") = 0
ds.Tables("Players").Rows.Add(dsNewRow)
da.Update(ds, "Players")
Call NewVillage(playerName, playerID)
End Sub
getLastIdent子例程是我尝试查找玩家ID字段中使用的最后一个值;
Public Function getLastIdent(ByVal tblname As String)
Dim sql As String = "SELECT @@IDENTITY FROM " & tblname
Dim cmd As New OleDb.OleDbCommand(Sql, con)
Return cmd.ExecuteScalar()
End Function
但这根本不起作用(无论如何都返回0)。玩家实际上可以毫无障碍地创建(错误的ID号似乎在数据库正确递增自动编号的某个时刻自行修复。但是为了给新玩家分配一个村庄我运行NewVillage;
Public Sub NewVillage(ByVal playerName As String, ByVal playerID As Integer)
Dim numVils As Integer = getVilCount()
Dim xpos As Integer
Dim ypos As Integer
xpos = CInt(Rnd()*50)
ypos = CInt(Rnd()*50)
Dim dsNewRow As DataRow
Dim Sql As String
Sql = "SELECT * FROM Villages"
da = New OleDb.OleDbDataAdapter(Sql, con)
da.Fill(ds, "Villages")
Dim cb As New OleDb.OleDbCommandBuilder(da)
dsNewRow = ds.Tables("Villages").NewRow()
dsNewRow.Item("ID") = numVils + 1
dsNewRow.Item("NameV") = playerName & "'s Village"
dsNewRow.Item("Xpos") = xpos
dsNewRow.Item("Ypos") = xpos
dsNewRow.Item("Owner") = playerID
ds.Tables("Villages").Rows.Add(dsNewRow)
da.Update(ds, "Villages")
End Sub
这就是整个事情崩溃的地方。传递给子程序的playerID不是与我刚刚创建的玩家相关联的正确值(面对那个名称没有任何玩家,因为它总是尝试playerID = 1并且AutoNumber开始高于到期时间删除失败的行)。
那么如何才能从玩家表中获取ID的真实价值呢?是否有一些我可以强制要求AutoNumber更新的调用,然后我可以重新检查它?
答案 0 :(得分:1)
我过去所做的是挂钩OleDbDataAdapter的RowUpdated事件,并在该钩子中执行身份检索命令。
首先,定义将用于在模块级别执行identity子句的命令,并添加一个方法来实例化它:
Private cmdGetIdentity As OleDb.OleDbCommand
Private Sub CreateIdentityCommand(con As OleDbConnection, tblName As String)
Dim sql As String = "SELECT @@IDENTITY FROM " & tblName
cmdGetIdentity = New OleDb.OleDbCommand(sql, con)
End Sub
接下来,创建将用于检索标识的事件处理程序(因为每个表都包含一个ID列,此代码可用于两个表):
Private Sub RowUpdated(ByVal sender As Object, ByVal e As OleDbRowUpdatedEventArgs)
If e.Status = UpdateStatus.Continue AndAlso e.StatementType = StatementType.Insert Then
' Execute the command and move it into the row
e.Row("ID") = Int32.Parse(cmdGetIdentity.ExecuteScalar().ToString())
' Ensure the row's changes are accepted
e.Row.AcceptChanges()
End If
End Sub
最后,修改现有方法以实例化identity命令,挂钩新事件,并删除尝试设置ID的现有代码。例如,在NewVillage中,更改:
da = New OleDb.OleDbDataAdapter(Sql, con)
到
da = New OleDb.OleDbDataAdapter(Sql, con)
CreateIdentityCommand(con, "Villages")
AddHandler da.RowUpdated, AddressOf RowUpdated
然后删除这些行:
Dim numVils As Integer = getVilCount()
和
dsNewRow.Item("ID") = numVils + 1