提问人:Andrew G. Johnson 提问时间:12/25/2008 最后编辑:CommunityAndrew G. Johnson 更新时间:5/27/2015 访问量:1542
对于每个在VBA代码中无法正常工作
For each not working properly in VBA code
问:
好吧,我几乎完成了我在这里讨论的应用程序的审计部分。我这样做的方式是遍历所有文本字段、下拉框和复选框,并将它们的值存储在 form_load 事件中。然后我在form_afterUpdate事件中做同样的事情,并将两者进行比较。如果有差异,我会记录它,如果没有,我会继续前进。代码如下:
Dim strValues(1 To 32) As String
Private Sub Form_AfterUpdate()
Dim strCurrentValue, strSQL As String
Dim intCurrentField As Integer
intCurrentField = 1
For Each C In Forms!frmVendorsManageVendors.Controls
Select Case C.ControlType
Case acTextBox, acComboBox, acCheckBox
//Doing this because I don't want a NULL as it won't concatenate in the SQL query and don't want 0 or -1 for the boolean fields
strCurrentValue = IIf(IsNull(C), "", IIf(C = vbTrue Or C = vbFalse, IIf(C = vbTrue, "Yes", "No"), C))
If strValues(intCurrentField) <> strCurrentValue Then
strSQL = "INSERT INTO changesTable (change_time,user_affected,field_affected,old_value,new_value) VALUES (NOW()," & [id] & ",'" & C.ControlSource & "','" & strValues(intCurrentField) & "','" & strCurrentValue & "')"
DoCmd.SetWarnings False
DoCmd.RunSQL strSQL
//InputBox "", "", strSQL
strSQL = "WEEEE"
DoCmd.SetWarnings True
strValues(intCurrentField) = strCurrentValue
End If
intCurrentField = intCurrentField + 1
End Select
Next
End Sub
Private Sub Form_Open(Cancel As Integer)
Call btnLock_Click
Dim intCurrentField As Integer
intCurrentField = 1
For Each C In Forms!frmVendorsManageVendors.Controls
Select Case C.ControlType
Case acTextBox, acComboBox, acCheckBox
//Doing this because I don't want a NULL as it won't concatenate in the SQL query and don't want 0 or -1 for the boolean fields
strValues(intCurrentField) = IIf(IsNull(C), "", IIf(C = vbTrue Or C = vbFalse, IIf(C = vbTrue, "Yes", "No"), C))
intCurrentField = intCurrentField + 1
End Select
Next
End Sub
正如你所看到的,有一个注释掉的行,我插入到changesTable中,它将查询放在一个输入框中,这样我就可以复制/粘贴它并查看它。当我取消注释该行时,一切都很好。如果它被注释,则会生成第一个更改,但随后不会为其他控件更改它。因此,如果我更改字段 1 和字段 2,它将插入字段 1 更改两次。
这非常令人困惑,我不知道为什么会发生这种情况。
我也知道我使用了错误的注释语法,但是如果我使用正确的语法,SO“代码颜色”er将无法正确显示。
答:
我猜 AfterUpdate 可能不是正确的事件。
此外,放置输入框可能会导致现有控件失去焦点(从而使其行为正确)。
我建议通过在选择大小写之后将 msgbox C.name 放入循环中来检查您的每个控件是否正在运行。
评论
我不确定我有完整的答案,但有几点观察。
可以使用 CurrentDB.Execute strSQL 消除某些代码行。这样就不需要 SetWarnings 调用。它直接针对数据库执行,而不与通常的接口机制交互。
出于调试目的,最好使用 Debug.Print 将 SQL 字符串放到“调试”窗口中。它避免了涉及用户界面,但仍然将 SQL 放在您可以将其复制到剪贴板的位置,如果您想获取它并使用它。
我认为执行 SQL 的 DoCmd 方法调用(即使调用 SetWarnnigs)的可能性很小,也可能在界面中倾斜一些东西以将焦点从表单上移开,就像 shahkalpesh 建议的那样。我已经做过这样的事情,但没有看到你遇到的问题,所以我对问题本身的唯一建议是像我一样做,切换到 CurrentDB.Execute 并消除循环中对 DoCmd 的调用。
只是好奇 -- 为什么你对以前的值使用数组,而不是在控件上使用 OldValue 属性?
您是否尝试过使用执行语句(类似这样)来执行此操作?
Dim db As DAO.Database 'Inside the transaction.
Set db = CurrentDB
strSQL = "INSERT INTO changesTable (change_time, user_affected, " & _
"field_affected, old_value, new_value) VALUES (NOW()," & [id] & _
",'" & C.ControlSource & "','" & strValues(intCurrentField) & _
"','" & strCurrentValue & "')"
db.Execute strSql
评论