You need to enable JavaScript to run this app. Access变更追踪代码仅在按Shift打开数据库时生效问题求助
优惠活动
大模型
产品
解决方案
定价
更多

Access变更追踪代码仅在按Shift打开数据库时生效问题求助

问题原因及解决方案

核心原因

你遇到的仅按住Shift启动功能才生效的问题,本质是Access默认启动和Shift启动的运行机制差异导致的:

  • Shift启动会默认跳过所有安全限制、启动项配置、记录集缓存策略,临时授予最高运行权限,同时关闭表单绑定数据的本地缓存
  • 正常启动时触发问题的常见诱因如下:
    • 数据库未加入受信任位置,VBA事件执行被宏安全策略限制,部分代码未完全生效
    • 表单绑定表的本地缓存未刷新:BeforeUpdate时修改还未提交到物理表,AfterUpdate时缓存未刷新导致两次SELECT查询拿到的都是修改前的旧值,因此比对无差异
    • 自动启动的表单实例和代码调用的CurrentDb会话不统一,导致读写数据出现延迟

修复方案

基础配置修复

先将数据库存放文件夹添加到Access受信任列表,消除安全限制:

  1. 打开Access,点击「文件」>「选项」>「信任中心」>「信任中心设置」
  2. 选择「受信任位置」,点击「添加新位置」,选择你存放数据库的文件夹后保存,重启数据库测试

代码逻辑优化(推荐,彻底避免缓存问题)

不需要通过查询物理表拿新旧值,直接用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.15 23:45:02