VBA DAO.Recordset 在尝试关闭它时为空或未设置 - 但我事先检查它是不是为空

Posted

技术标签:

【中文标题】VBA DAO.Recordset 在尝试关闭它时为空或未设置 - 但我事先检查它是不是为空【英文标题】:VBA DAO.Recordset is null or not set when trying to close it - But I check if its null beforehandVBA DAO.Recordset 在尝试关闭它时为空或未设置 - 但我事先检查它是否为空 【发布时间】:2017-10-15 03:54:18 【问题描述】:

在访问应用程序的 VBA 代码中,有一个函数可以将某些数据库字段转换为另一种格式。这发生在 2 个表中,在代码中,您可以通过 2 个循环告诉它们,用于 BOM 和 ROUTING。这段代码的性能很差,因为有时有 200000+ 条记录通过它。为了加快它的速度,我向它添加了交易——它现在的速度是原来的 3 倍。但是,当尝试关闭 ROUTING 记录集时,我收到一条错误消息,提示“对象无效或不再设置”。因此,我在尝试关闭它之前添加了 2 个检查,不是空的,也不是空的。当使用调试器单步执行时,它通过了两项检查,然后尝试关闭记录集,然后转到提供消息的 ErrorHandler。使这个错误更加奇怪的是它在关闭第一个循环的 BOM 记录集时没有问题。 代码:

Public Sub SomeSub()
    ' set up variables
    Dim BOM As DAO.Recordset
    Dim ROUTING As DAO.Recordset

    Dim Workspace As DAO.Workspace
    Set Workspace = DBEngine.Workspaces(0)

    ' set up errorhandler
    On Error GoTo ErrorHandler

    ' run some process on BOM
    Set BOM = CurrentDb.OpenRecordset("some query;", dbOpenDynaset, dbSeeChanges, dbOptimistic)
    Workspace.BeginTrans
    If Not (BOM.BOF And BOM.EOF) Then
        BOM.MoveFirst
        Do While (Not BOM.EOF) And (Not BOM.BOF)
            ' Do some stuff with BOM here
            BOM.MoveNext
        Loop
    End If
    Workspace.CommitTrans
    BOM.Close
    Set BOM = Nothing



    Set ROUTING = CurrentDb.OpenRecordset("some query;", dbOpenDynaset, dbSeeChanges, dbOptimistic)
    Workspace.BeginTrans
    If Not (ROUTING.BOF And ROUTING.EOF) Then
        ROUTING.MoveFirst

        Do While (Not ROUTING.EOF)
            ' Do some stuff with ROUTING here
            ROUTING.MoveNext

        Loop
    End If

    Workspace.CommitTrans
    Workspace.Close

    If Not ROUTING Is Nothing Then
        If Not ROUTING Is Null Then
            ROUTING.Close
        End If
    End If

    GoTo SuccesHandler
ErrorHandler:
    MsgBox "Ran into error. Info: " & Err.number & ": " & Err.DESCRIPTION & vbNewLine
    Resume SuccesHandler
SuccesHandler:
End Sub

问题: - 为什么会发生这个错误? - null/nothing 检查的正确方法是什么? (显然我这样做的方式不起作用?)

【问题讨论】:

【参考方案1】:

您需要先关闭Recordset,然后再关闭Workspace

Workspace.CommitTrans

If Not ROUTING Is Nothing Then
    ROUTING.Close
    Set ROUTING= Nothing
End If

Workspace.Close
Set Workspace = Nothing

【讨论】:

这行得通。代码现在运行良好,谢谢!我想知道为什么。工作区是否与您在事务中实例化或更新的所有 DAO 记录有关?关闭工作区是否会关闭所有使用所述工作区更新的记录集?【参考方案2】:

我会调整该块以匹配有效的块 - 并将工作区处理移出该块:

Set ROUTING = CurrentDb.OpenRecordset("some query;", dbOpenDynaset, dbSeeChanges, dbOptimistic)
Workspace.BeginTrans
If Not (ROUTING.BOF And ROUTING.EOF) Then
    ROUTING.MoveFirst
    Do While (Not ROUTING.EOF)
        ' Do some stuff with ROUTING here
        ROUTING.MoveNext
    Loop
End If
Workspace.CommitTrans
ROUTING.Close
Set ROUTING = Nothing

Set Workspace = Nothing

【讨论】:

这行得通。代码现在运行良好,谢谢!我想知道为什么。工作区是否与您在事务中实例化或更新的所有 DAO 记录有关?关闭工作区是否会关闭所有使用所述工作区更新的记录集? 您不应该关闭当前工作区,就像您从不关闭 CurrentDb 一样。此外,一个常见的规则是始终按照打开对象的相反顺序将对象设置为 Nothing。这在 Access 中很少出现问题,但在 Excel 中可能会导致严重的问题。 所以我应该使用全局定义的工作区,定义方式与 CurrentDB 相同? 是的,这样做。您也可以将CurrentDb 替换为您设置为WorkSpace(0)DAO.Database 对象。

以上是关于VBA DAO.Recordset 在尝试关闭它时为空或未设置 - 但我事先检查它是不是为空的主要内容,如果未能解决你的问题,请参考以下文章

使用 DAO.Recordset 编辑、更新记录

DAO.Recordset.Update 导致记录锁

使用 FindFirst 时出现 DAO RecordSet 错误 3251

通过(动态)名称声明一个新的 DAO.Recordset

DAO.Recordset MySQL 后端在字符串周围强制使用单引号

VBA公式不会计算[关闭]