Access变更追踪代码仅在按Shift打开数据库时生效问题求助
问题原因及解决方案
核心原因
你遇到的仅按住Shift启动功能才生效的问题,本质是Access默认启动和Shift启动的运行机制差异导致的:
- Shift启动会默认跳过所有安全限制、启动项配置、记录集缓存策略,临时授予最高运行权限,同时关闭表单绑定数据的本地缓存
- 正常启动时触发问题的常见诱因如下:
- 数据库未加入受信任位置,VBA事件执行被宏安全策略限制,部分代码未完全生效
- 表单绑定表的本地缓存未刷新:BeforeUpdate时修改还未提交到物理表,AfterUpdate时缓存未刷新导致两次SELECT查询拿到的都是修改前的旧值,因此比对无差异
- 自动启动的表单实例和代码调用的CurrentDb会话不统一,导致读写数据出现延迟
修复方案
基础配置修复
先将数据库存放文件夹添加到Access受信任列表,消除安全限制:
- 打开Access,点击「文件」>「选项」>「信任中心」>「信任中心设置」
- 选择「受信任位置」,点击「添加新位置」,选择你存放数据库的文件夹后保存,重启数据库测试
代码逻辑优化(推荐,彻底避免缓存问题)
不需要通过查询物理表拿新旧值,直接用Access表单内置的OldValue属性获取修改前的值,对比当前控件值即可,完全绕过缓存问题:
' 模块顶部声明存储旧值的数组,或者直接在BeforeUpdate里存到变量 Dim arrOldVals() As Variant Dim fldCount As Integer Private Sub Form_BeforeUpdate(Cancel As Integer) Dim i As Integer bWasNewRec = Me.NewRecord If Me.Ingevoerd = True And Not bWasNewRec Then fldCount = Me.Recordset.Fields.Count ReDim arrOldVals(fldCount - 1, 1) ' 直接从表单记录集拿旧值,不需要查物理表 For i = 0 To fldCount - 1 arrOldVals(i, 0) = Me.Recordset.Fields(i).Name arrOldVals(i, 1) = Nz(Me.Recordset.Fields(i).OldValue, "-") Next End If End Sub Private Sub Form_AfterUpdate() Dim recEdited As DAO.Recordset Dim sUN As String Dim i As Integer sUN = Environ("UserName") If Me.Ingevoerd = True And Not bWasNewRec Then Set recEdited = CurrentDb.OpenRecordset("SELECT * FROM ChangeLog") For i = 0 To fldCount - 1 ' 直接拿当前新值和存储的旧值对比 If Nz(Me.Recordset.Fields(i).Value, "-") <> arrOldVals(i, 1) Then recEdited.AddNew recEdited.Fields(2).Value = Now() recEdited.Fields(3).Value = sUN recEdited.Fields(4).Value = "tbl_Planning" recEdited.Fields(5).Value = Nz(Me!TOS.Value, "-") recEdited.Fields(6).Value = Nz(Me!Startdatum.Value, "-") recEdited.Fields(7).Value = Me!planningID.Value recEdited.Fields(8).Value = Nz(Me!ID_nummer.Value, "-") recEdited.Fields(9).Value = arrOldVals(i, 0) recEdited.Fields(10).Value = arrOldVals(i, 1) recEdited.Fields(11).Value = Nz(Me.Recordset.Fields(i).Value, "-") recEdited.Update End If Next recEdited.Close Set recEdited = Nothing Erase arrOldVals End If End Sub
原有逻辑最小修改方案
如果不想调整现有代码结构,只需要在AfterUpdate事件的INSERT语句前加一行强制刷新缓存的代码即可:
' 插入到temp_AfterUpdate之前添加这行 DBEngine.Idle dbRefreshCache sSQL = "INSERT INTO temp_AfterUpdate ( changedType, changedDate, changedUser, tbl_ID ) " & _ "SELECT 'NewVal' AS Expr1, Now() AS Expr2, '" & sUN & "' AS Expr3, " & Me.planningID & " as Expr4, * FROM tbl_Planning WHERE planningID = " & Me.planningID & ";" CurrentDb.Execute sSQL
内容的提问来源于stack exchange,提问作者Vanegh
相关产品推荐
相关产品推荐

