VB 2019直接读写DataTable实现变更审计追踪的技术咨询
问题背景与需求
我的应用用于管理建筑项目,产品订购前项目会经历多次变更。我需要创建变更审计追踪,实现以下目标:
- 向客户核实或解释变更
- 发现并纠正错误与违规行为
具体规则:
- 在内存中保存当前记录的副本
- 保存记录时将其与内存副本对比,若存在变更,则在同一张表中新增一条包含原始数据的记录
- 新增记录的
DateChanged字段设为当前日期时间(原始记录该字段为null) User_ID字段记录创建该记录的用户
遇到的问题
我需要操作未在用户表单上展示的数据,但不想用隐藏文本控件(这种方式太笨拙)。我知道可以直接操作DataTable,但找不到易懂可运行的VB 2019示例——现有示例要么是VB6版本(我懂但没有编译器/IDE,Windows 10上难运行且无官方支持),要么依赖代码外的参数。我希望完全不涉及表单,直接读写DataTable。
表结构
| 字段名 | 类型 | 说明 |
|---|---|---|
| Author | 短文本 | 主键 |
| Year_Born | 整数 | |
| User_ID | 短文本 | |
| DateChanged | 日期/时间 |
VB 2019示例代码
' Visual Basic 2019. 数据库用Access 2019创建。 ' 目标CPU已设置为x64。 ' 通过NuGet添加了system.data.oledb,版本6.00。 ' 添加了"Microsoft ActiveX Data Objects 6.1 Library"引用 Imports System.Data Imports System.Data.OleDb Public Class frmAuthor Dim BooksConnection As OleDbConnection Dim AuthorsCommand As OleDbCommand Dim AuthorsAdapter As OleDbDataAdapter Dim AuthorsTable As DataTable Dim AuthorsManager As CurrencyManager ' 这里的Currency指"保持当前记录",不是货币 Dim MyState As String = "View" ' 用于记录状态切换 Dim MyBookmark As Integer ' 用于取消新增操作 Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load BooksConnection = New OleDbConnection ' (ConnectionString) BooksConnection.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0; " _ + "Data Source = C:\VBDB\BooksDb.accdb" BooksConnection.Open() AuthorsCommand = New OleDbCommand("SELECT * from Authors ORDER BY Author", BooksConnection) AuthorsAdapter = New OleDbDataAdapter() AuthorsAdapter.SelectCommand = AuthorsCommand AuthorsTable = New DataTable() AuthorsAdapter.Fill(AuthorsTable) txtAuthorName.DataBindings.Add("Text", AuthorsTable, "Author") txtYearBorn.DataBindings.Add("Text", AuthorsTable, "Year_Born") AuthorsManager = DirectCast(Me.BindingContext(AuthorsTable), CurrencyManager) Me.Show() Call SetState("View") End Sub End Class
解决方案思路
1. 保存原始记录副本
在进入编辑状态时,直接从AuthorsTable中复制当前行的原始数据,无需依赖表单控件:
' 编辑前保存当前行的原始副本 Dim originalRow As DataRow = AuthorsTable.Rows(AuthorsManager.Position).Copy()
2. 对比变更并生成审计记录
保存时,将当前行与原始副本对比,判断是否有变更,若有则生成审计记录:
Dim currentRow As DataRow = AuthorsTable.Rows(AuthorsManager.Position) Dim hasChanges As Boolean = False ' 遍历字段对比(排除审计专用字段) For Each col As DataColumn In AuthorsTable.Columns If col.ColumnName <> "DateChanged" And col.ColumnName <> "User_ID" Then If Not Object.Equals(currentRow(col), originalRow(col)) Then hasChanges = True Exit For End If End If Next If hasChanges Then ' 新建审计记录行 Dim auditRow As DataRow = AuthorsTable.NewRow() ' 复制原始行数据 auditRow.ItemArray = originalRow.ItemArray ' 设置审计字段值 auditRow("DateChanged") = DateTime.Now auditRow("User_ID") = "当前用户ID" ' 替换为实际登录用户ID ' 将审计记录添加到DataTable AuthorsTable.Rows.Add(auditRow) ' 同步更新到数据库 Dim commandBuilder As New OleDbCommandBuilder(AuthorsAdapter) AuthorsAdapter.Update(AuthorsTable) End If
3. 关键注意事项
- 全程直接通过
DataRow和DataTable操作所有字段,包括未在表单显示的User_ID和DateChanged,无需隐藏控件 - 使用
OleDbCommandBuilder自动生成数据库操作命令,无需手动编写SQL - 确保数据库表中
DateChanged字段允许为null(原始记录该字段值为null) - 主键冲突处理:若
Author作为单一主键,新增审计记录时可能冲突,建议修改表结构增加自增审计ID作为主键,或设Author+DateChanged为复合主键(原始记录DateChanged为null,不会与审计记录冲突)
内容的提问来源于stack exchange,提问作者BitTwiddler
相关产品推荐
相关产品推荐

