---- 在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  
|