---- 在VB5.0 中, 用Microsoft Jet 数 据 库 引 擎 和 数 据 访 问 对 象DAO(Data Access Object) 可 以 创 建 功 能 强 大 的 客 户/ 服 务 器 应 用 程 序。 对 远 程 数 据 库 的 访 问 是 开 发 这 类 应 用 程 序 的 关 键 环 节, 本 文 将 介 绍 在VB5.0 中 用DAO 通 过Miscrosoft Jet 数 据 库 引 擎 访 问 远 程 数 据 库 的 方 法。
---- 用DAO 访 问 远 程 数 据 库 大 体 上 可 以 通 过 三 步 来 实 现, 即 数 据 连 接、 数 据 处 理 和 断 开 连 接。 下 面 主 要 介 绍 数 据 连 接 和 数 据 处 理 的 具 体 操 作。
---- 一、 数 据 连 接
---- DAO 一 般 通 过 链 接 远 程 表 的 方 式 来 进 行 数 据 连 接。 这 样, 数 据 虽 然 驻 留 在 远 程 数 据 源 上, 但 在 本 地 的Microsoft Jet 数 据 库 中 可 以 存 储 与 远 程 数 据 的 永 久 性 连 接, 同 时 缓 存 链 接 的 表 结 构 信 息, 从 而 在 下 一 次 访 问 该 表 时, 不 用 再 次 从 服 务 器 中 检 索 这 些 结 构 信 息, 加 快 了 连 接 速 度。 一 旦 链 接 了 一 个 表, 该 链 接 便 会 保 留 在 各 会 话 期 间, 直 到 连 接 断 开。 链 接 远 程 表 的 具 体 操 作 是:
用OpenDatabase 方 法 打 开 将 要 包 含 该 链 接 的 本 地Microsoft Jet 数 据 库
用CreateTableDef 方 法 在 该 数 据 库 中 创 建 一 个 新 的TableDef 对 象
将TableDef 对 象 的Connect 属 性 设 置 为 一 个 合 法 的 连 接 字 符 串, 标 识 要 访 问 的 远 程 数 据 库 类 型、 数 据 文 件 的 路 径 以 及 用 户 名 和 远 程 数 据 源 密 码 等。
将TableDef 对 象 的SourceTableName 属 性 设 置 为 远 程 数 据 库 中 要 访 问 的 表 的 名 称。
添 加TableDef 对 象 到TableDefs 集 合 中。
---- 实 现 链 接 远 程 表 操 作 的 过 程 如 下:
Public Sub LinkTable(strDB As String, strRoDB As String,
strCn As String, strTdf As String, _
linkTdfName As String)
Dim linkTdf As New TableDef
Set dbs = OpenDatabase(strDB)
linkTdf.Name = linkTdfName
100
tempTable = UCase(linkTdf.Name)
For i = 0 To dbs.TableDefs.Count - 1
If UCase(dbs.TableDefs(i).Name) = tempTable Then
If MsgBox(linkTdfName + " 已存在,是否删除 ?", _
vbQuestion + vbYesNo) = vbYes Then
dbs.TableDefs.Delete linkTdf.Name
Exit For
Else: MsgBox "重新输入新表名"
linkTdfName = InputBox(" 新表名")
GoTo 100
End If
End If
Next i
Set linkTdf = dbs.CreateTableDef
(linkTdfName) '链接远程表
linkTdf.Connect = ";database=" + strCn
linkTdf.SourceTableName = strTdf
dbs.TableDefs.Append linkTdf
End Sub
---- 上 述 过 程 用 来 实 现 远 程 表 的 连 接, 它 有5 个 参 数, 其 中strRoDB 是 要 访 问 的 远 程 数 据 库 名( 包 括 路 径);strTdf 是 该 数 据 库 中 的 表 名;strDB 是 要 链 接 的 本 地 数 据 库( 包 括 路 径);linkTdfName 是 本 地 数 据 库 的 一 个 新 表 名, 用 来 建 立 远 程 表 的 链 接;strCn 是 指 定 连 接 信 息 的 字 符 串。 需 要 特 别 注 意 的 是, 除 了 在 访 问 远 程Microsoft Jet 数 据 库 时, 连 接 字 符 串 要 以 分 号(;) 开 头 外, 指 定 连 接 信 息 的 字 符 串 都 必 须 以 所 访 问 的 远 程 数 据 库 类 型 开 头。DAO 可 以 访 问 的 远 程 数 据 源 有 以 下 三 类:
Microsoft Jet 数 据 源, 如:Access 数 据。
IISAM( 可 安 装 的 索 引 化 顺 序 访 问 方 法) 格 式 数 据 源, 如:FoxPro、Paradox、dBASE 数 据。
ODBC 数 据 源, 如:SQL Server 数 据、Oracle 数 据。
---- 例 如: 设 网 络 服 务 器 名 为server, 共 享 目 录 为C:\Sales 的FoxPro 3.0 数 据 库, 连 接 字 符 串 应 为
---- strCn="FoxPro3.0;database=\\server\c$\Sales\Region1"
---- 此 外,DAO 通 过Microsoft Jet 数 据 库 引 擎 访 问 远 程 数 据 时, 还 可 以 用OpenDatabase 方 法 直 接 打 开 远 程 表。 在 本 地 数 据 库 中 并 未 存 储 与 远 程 数 据 源 建 立 连 接 所 需 要 的 信 息。 如 果 使 用 链 接 方 式 访 问 数 据, 则 不 必 在 每 次 会 话 开 始 时 提 供 连 接 信 息, 从 而 可 以 提 高 效 率。
---- 二、 数 据 处 理
---- 数 据 连 接 建 立 后, 可 以 用OpenRecordset 方 法 打 开 一 个 记 录 集, 并 可 用DBGrid 控 件 和Data 控 件 方 便 地 浏 览 整 个 记 录 集。 如 果 使 用 表 类 型(Table-type) 记 录 对 象, 则 对 应 的 是 一 个 实 际 存 在 的 数 据 库 表, 在 多 用 户 环 境 下, 其 它 用 户 对 数 据 的 修 改 会 立 即 反 映 到 表 中; 如 果 使 用 动 态 集 类 型(Dynaset-type) 记 录 对 象, 则 对 应 的 既 可 以 是 一 个 表 中 全 部 记 录, 又 可 以 是 一 个 查 询 的 结 果, 并 且 可 以 更 新 记 录 集 中 的 记 录; 如 果 使 用 快 照 类 型(Snapshot-type) 记 录 对 象, 则 对 应 的 可 以 是 表 中 的 全 部 记 录, 也 可 以 是 一 个 查 询 结 果, 但 不 能 进 行 记 录 的 增 加、 删 除 和 修 改 操 作。 此 外, 还 可 以 建 立 其 它 类 型 的 记 录 对 象, 如 仅 向 前 型(ForwardOnly-type) 记 录 对 象 和 动 态 型(Dynamic-type) 记 录 对 象。
---- 下 面 是 打 开 动 态 集 记 录 对 象 并 显 示 记 录 的 过 程:
Public Sub rst_display(strDB As String,
strRst As String, strForm As Form)
Set dbs = OpenDatabase(strDB)
Set rst = dbs.OpenRecordset(strRst, dbOpenDynaset)
strForm!Data1.DatabaseName = dbs.Name
strForm!Data1.RecordSource = rst.Name
strForm!Data1.Refresh
strForm!DBGrid1.ReBind
End Sub
---- 上 述 过 程 有 三 个 参 数, 其 中strDB 用 来 指 定 本 地 数 据 库 名( 包 括 路 径),linkTdfName 是 在 本 地 数 据 库 中 新 建 的 链 接 远 程 表 的 表 名,strForm 是 网 格 控 件 和 数 据 控 件 所 在 的 窗 体 名。 调 用 此 过 程 可 以 基 于 新 表 建 立 一 个 动 态 集 类 型 的 记 录 对 象, 并 可 在 网 格 中 浏 览 各 个 记 录。
---- 断 开 连 接 可 以 通 过 关 闭 应 用 程 序 或 设 置 连 接 超 时 来 实 现。 注 意: 如 果 对 数 据 库 对 象 使 用Close 方 法, 则 由 于 在Miscrosoft Jet 数 据 库 引 擎 内 部 缓 存 了 连 接, 实 际 上 连 接 并 未 取 消。
---- 三、 应 用 举 例
---- 以 上 介 绍 了 用DAO 访 问 远 程 数 据 库 的 具 体 操 作, 下 面 通 过 一 个 例 子 说 明 链 接 远 程 表 和 建 立 记 录 集 对 象 的 方 法。
---- 首 先 建 立 一 个 新 工 程, 在 窗 体 上 画5 个 命 令 按 钮,1 个 数 据 控 件 和1 个 数 据 网 格 控 件(DBGrid), 各 对 象 的 属 性 设 置 见 表1。
表1 窗体1对象属性设置 对象 标题(Caption) 名称(Name)
窗体 远程数据访问 Form1
命令按钮1 链接远程表 cmd链接
命令按钮2 添加 cmdAdd
命令按钮3 删除 cmdDel
命令按钮4 修改 cmdModify
命令按钮5 结束 cmdEnd
数据控件 Data1 Data1
数据网格 DBGrid1
---- 其 中DBGrid1 中 的DataSource 属 性 设 为Data1, 命 令 按 钮2,3,4 的Visible 属 性 设 为False。
---- 编 写 如 下 事 件 过 程:
----
Private Sub cmdAdd_Click() '添加记录子过程
On Error GoTo errHandler
With rst
.AddNew
For i = 0 To .Fields.Count - 1 '遍历记录集中的每个字段
'在输入框中输入各字段的数据
.Fields(i).Value = InputBox
("输入记录信息" & vbCr + "字段名:" + .Fields(i).Name)
Next i
.Update
End With
Data1.Refresh
DBGrid1.ReBind
errHandler: '错误处理
Select Case Err
Case 3022, 3421
MsgBox (Error + vbCr + "输入无效")
Exit Sub
Case Else
Response = 0
Exit Sub
End Select
End Sub
Private Sub cmdDel_Click() '删除记录过程
On Error GoTo errHandler
BeginTrans '事务处理
With Data1.Recordset
If .BOF And .EOF Then Exit Sub '如果没有记录,退出过程
.Delete '删除
If .BOF And .EOF Then '如果没有记录,退出过程
Exit Sub
ElseIf .EOF Then .MoveLast
'如果删除的是最后一条记录,光标移至最后一记录
Else: .MoveNext '移至下一条记录
End If
End With
If MsgBox("确实要删除这一记录?",
vbQuestion + vbYesNo) = vbYes Then
CommitTrans '确认
Data1.Refresh
Else
Rollback '撤消改动
Data1.Refresh
End If
errHandler: '错误处理
Select Case Err
Case 3021 '无当前记录
MsgBox ("无当前记录,请选择要删除的记录")
Exit Sub
Case Else
MsgBox (Error)
Exit Sub
End Select
End Sub
Private Sub cmdEnd_Click()
End '结束应用程序
End Sub
Private Sub cmdModify_Click()
DBGrid1.AllowUpdate = True '允许修改
End Sub
Privatev Sub cmd链接_Click()
Form1.Hide
Form2.Show
End Sub
Private Sub DBGrid1_After
ColUpdate(ByVal ColIndex As Integer)
'数据修改后触发该事件
On Error GoTo err1
Data1.Refresh
err1:
Select Case Err
Case 0
Response = 0
Case Else
Exit Sub
End Select
End Sub
Private Sub DBGrid1_BeforeColUpdate(ByVal
ColIndex As Integer,
OldValue As Variant, Cancel As Integer)
'数据修改前触发该事件
On Error GoTo errHandler:
BeginTrans
If MsgBox("确实要修改这一内容?",
vbQuestion + vbYesNo) = vbYes Then
CommitTrans
Else
Rollback
Data1.Refresh
End If
errHandler:
Select Case Err
Case 0
Response = 0
Case Else
MsgBox (Error)
Exit Sub
End Select
End Sub
Private Sub Form_Load()
'在窗体装入时,网格中的数据不可添加,修改
DBGrid1.AllowAddNew = False
DBGrid1.AllowUpdate = False
End Sub
Private Sub Form_Resize()
On Error Resume Next
'当窗体调整时会调整网格
DBGrid1.Height = Me.ScaleHeight
- Data1.Height - cmd删除.Height - 30
End Sub
---- 在 工 程 中 添 加 一 个 窗 体, 在 窗 体 上 画6 个 标 签,1 个 命 令 按 钮( 标 题 为" 确 认", 名 称 为cmd 确 认),3 个 文 本 框 和1 个 组 合 框 在 窗 体 的 声 明 部 份 输 入 以 下 代 码:
---- ' 声 明 窗 体 层 变 量
Dim rodbs As Database
Dim strDB As String, strRoDB
As String, strCn As String, strTdf As String
Dim linkTdfName As String
编写如下事件过程:
Private Sub cmd确认_Click()
On Error GoTo errHandler:
strDB = text2.Text '本地数据库名及路径
linkTdfName = Text3.Text
'本地数据库中新建的链接远程表的表名
strCn = strRoDB '连接字符串
strTdf = Combo1.Text
'指定远程数据库中要访问的表
'调用LinkTable过程
Call LinkTable(strDB,
strRoDB, strCn, strTdf, linkTdfName)
'调用rst_display过程
Call rst_display(strDB, linkTdfName, Form1)
Form2.Hide
Form1.Show
Form1.Caption =
"远程数据:" + strCn + "-" + strTdf
'显示"添加","删除","修改"控件
Form1.cmdAdd.Visible = True
Form1.cmdDel.Visible = True
Form1.cmdModify.Visible = True
errHandler:
Select Case Err
Case 0
Response = 0
Case Else
MsgBox (Error + vbr + "重新输入")
Exit Sub
End Select
End Sub
Private Sub Combo1_GotFocus()
strRoDB = text1.Text
'指定远程数据库名及路径
Set rodbs = OpenDatabase(strRoDB)
'打开远程数据库
'删除combo1中的内容
If Combo1.ListCount >= 1 Then
For i = Combo1.ListCount - 1 To 0 Step -1
Combo1.RemoveItem i
Next i
End If
'把数据库中的表名加到combo1中
For i = 0 To rodbs.TableDefs.Count - 1
Combo1.AddItem rodbs.TableDefs(i).Name
Next i
End Sub