【问题标题】:DoCmd.DeleteObject acTable - "could not lock table because it is already in use"DoCmd.DeleteObject acTable - “无法锁定表,因为它已在使用中”
【发布时间】:2015-11-29 14:13:21
【问题描述】:

尝试删除表时出现以下错误:

运行时错误'3211'

数据库引擎无法锁定表“RuleViolations1516”,因为 它已被其他人或进程使用。

这是有问题的程序,注释显示抛出错误的行:

Public Sub ImportRuleViolations()

    DoCmd.Close acForm, "frmImportRuleViolations"

    If _
        TableExists("RuleViolations1516") = True _
    Then

        Debug.Print "Table RuleViolations1516 already exists"

        DoCmd.DeleteObject acTable, "RuleViolations1516" ' <-- EXECUTION STOPS HERE
        Debug.Print "...old table deleted..."

        DoCmd.TransferSpreadsheet acTable, _
                  10, _
                  "RuleViolations1516", _
                  Forms!frmImportRuleViolations.txtRuleViolationsPath & Forms!frmImportRuleViolations.txtRuleViolationFile, _
                  -1
        Debug.Print "...new data imported."

    ElseIf _
        TableExists("RuleViolations1516") = False _
    Then

        Debug.Print "Table RuleViolations1516 does not already exist"

        DoCmd.TransferSpreadsheet acTable, _
                          10, _
                          "RuleViolations1516", _
                          Forms!frmImportRuleViolations.txtRuleViolationsPath & Forms!frmImportRuleViolations.txtRuleViolationFile, _
                          -1
        Debug.Print "...new data imported."

    End If

    Dim db As DAO.Database
    Dim tDef As TableDef, fld As DAO.Field

    Set db = CurrentDb

    db.TableDefs.Refresh

    ' LRN

        Set tDef = db.TableDefs("RuleViolations1516")
        Set fld = tDef.CreateField("newLRN", dbText, 20)
        fld.OrdinalPosition = 2
        tDef.Fields.Append fld

        db.Execute _
            "UPDATE RuleViolations1516 Set newLRN=[Learner Ref]", dbFailOnError

        ' delete old field
        tDef.Fields.Delete "Learner Ref"
        tDef.Fields.Refresh

        ' rename new field
        tDef.Fields("newLRN").name = "LRN"
        tDef.Fields.Refresh

        Set fld = Nothing
        Set tDef = Nothing

    ' AimRef

        Set tDef = db.TableDefs("RuleViolations1516")
        Set fld = tDef.CreateField("newAimRef", dbText, 20)
        fld.OrdinalPosition = 7
        tDef.Fields.Append fld

        db.Execute _
            "UPDATE RuleViolations1516 Set newAimRef=[Aim Reference Number]", dbFailOnError

        ' delete old field
        tDef.Fields.Delete "Aim Reference Number"
        tDef.Fields.Refresh

        ' rename new field
        tDef.Fields("newAimRef").name = "AimRef"
        tDef.Fields.Refresh

        Set fld = Nothing
        Set tDef = Nothing

    Set db = Nothing

    DoCmd.OpenForm "frmImportRuleViolations"

End Sub

有问题的 sub 还引用了另一个函数:

Public Function TableExists(name As String) As Boolean

    TableExists = DCount("*", "MSysObjects", "Name = '" & name & "' AND Type = 1")

End Function

上面的 sub 和 function 在它们自己的单独模块上运行(不绑定到表单模块)。

当我运行 sub 时,表 RuleViolations1516 未打开。 frmImportRuleViolations 表单在某些子表单后面的某些查询中使用了 RuleViolations1516 表,但是从子表单中可以看到,我已经在第一行关闭了此表单。

任何指针将不胜感激。

更新:

frmImportRuleViolations 上有 2 个子表单...删除它们(暂时)停止问题。我需要表单上的子表单.. 我该如何解决这个问题?

【问题讨论】:

  • 如果在 if 语句之前执行 DoCmd.DeleteObject 会发生什么?它在那里也失败了吗?
  • 仅作为测试,如果您删除或禁用DoCmd.Close acForm, "frmImportRuleViolations",然后在 frmImportRuleViolations 关闭时运行 ImportRuleViolations,是否仍会得到相同的结果错误?
  • @BIBD 我注释掉了该子代码中的所有代码,除了DoCmd.DeleteObject 行。发生同样的错误。
  • @HansUp 我为表单创建了一个关闭按钮,并在其点击事件中添加了DoCmd.Close acForm, "frmImportRuleViolations" 行。然后,我在表单的关闭事件中调用了 ImportRuleViolations 子(希望这就是您的意思)。发生同样的错误。
  • 我已经为我的问题添加了一个更新。似乎我的主表单上的子表单导致了这个问题……但不知道如何解决这个问题。

标签: ms-access vba ms-access-2007 ms-access-2010 ms-access-2013


【解决方案1】:

据我了解您更新后的问题,您有一个名为 frmImportRuleViolations 的表单,它有一个子表单,我将调用 frmImportRuleViolationsSubform1

frmImportRuleViolationsSubform1 引用了上面某处的RuleViolations1516 表。

我假设您还通过frmImportRuleViolations 上的按钮或其他控件触发了此重新加载。如果是这样,那么这是你错误的原因。到关闭事件时,Access 可能还没有放弃对RuleViolations1516 的所有引用。

这和关闭和重新打开自己的表单可能会有点麻烦。

一个相当简单的事情是在打开 frmImportRuleViolationsSubform1 之前删除并加载表。作为用户(和开发人员),这是我所期望的——我打开表单,它是最新的。最坏的情况是关闭表单并重新打开它让我刷新。

失败(它绝对必须在表单关闭后重新加载);然后我将关闭它的任何东西打开frmImportRuleViolations作为模式窗口,然后在调用frmImportRuleViolations之后重新加载表代码,因为它会等到控制权返回到调用窗口。

您也可以将数据加载到临时临时表中,然后删除 RuleViolations1516 的内容并从临时表中重新填充。这可能是我会采取的路线,因为它将消除frmImportRuleViolations 表单的关闭和打开。您只需要告诉子表单上的表格进行刷新(我将为读者留下一个练习)。


除此之外,还有一些风格说明:

'' this 
If _
    TableExists("RuleViolations1516") = True _
Then

'' could be equally written as
If TableExists("RuleViolations1516") Then
'' the "= True" is implied and not required

'' this
ElseIf _
    TableExists("RuleViolations1516") = False _
Then

'' is redundant to the previous if. A simple else would do, since we
'' know if the last time it ran, it wasn't true, it must be false

DoCmd 块看起来在 if 和 else 中做同样的事情,所以我倾向于像这样提取它:

If TableExists("RuleViolations1516") then
    Debug.Print "Table RuleViolations1516 already exists"
    DoCmd.DeleteObject acTable, "RuleViolations1516" 
    Debug.Print "...old table deleted..."
else
    Debug.Print "Table RuleViolations1516 does not already exist"
end if

DoCmd.TransferSpreadsheet acTable, _
    10, _
    "RuleViolations1516", _
    Forms!frmImportRuleViolations.txtRuleViolationsPath & _
        Forms!frmImportRuleViolations.txtRuleViolationFile, _
    -1
Debug.Print "...new data imported."

这样,当您回来更改文件名(或其他名称)时,您只需在一个地方进行更改,等等,并且符合 DRY 原则 - “DRY - 不要重复你自己”。

I like the use of underscores so that what you have coded does not run off the edge of the screen like some extract from war and peace. It makes it much more readable.

你所做的事情没有错。这不是大多数开发人员会做的事情。尽管我们为计算机编写代码以按照我们想要的方式运行,我们也希望下一个开发人员在 5 年后接触您的代码,以便轻松理解您在做什么。而且代码的持续时间总是比你想象的要长:^)

祝你好运!

【讨论】:

  • (1/3) 感谢所有这些指针 - 都非常有用。表单的关闭/打开不是预期设计的一部分,它只是我试图让 Access 放开桌子然后我把它留在我的问题中以显示桌子仍然是多么奇怪当所有使用它的东西都不再出现在屏幕上时,就被认为是打开的。数据的刷新来自表单上调用ImportRuleViolations()的命令按钮。
  • (2/3) 不幸的是,我无法完全自动刷新,因为它依赖于导入文件名可能不同的电子表格(因此用户必须使用文件对话框手动选择 .xlsx 文件:i.imgur.com/wMRLsxT.jpg)。我想出了简单地拆分表单的解决方法,这样就有一个单独的导入表单来处理获取新数据,然后在完成后用我的子表单打开表单。
  • (3/3) 感谢这些风格提示。我经常以一种非常明确的方式编写我的初始代码,直到我很高兴它一切正常......因此我倾向于使用隐含的= True= False 部分编写IF 语句(只是让它更容易让我最初扫描)。然后,当我有更多时间时,我通常会缩小事情的范围。你对TransferSpreadsheet的冗余使用是完全正确的;我有点马虎,感谢您发现这一点。即使我使用了不同的方法来解决这个问题,我也可以看到您提出的建议是合理的,因此我将其标记为答案。谢谢。
猜你喜欢
  • 1970-01-01
  • 2019-01-09
  • 2016-08-08
  • 1970-01-01
  • 1970-01-01
  • 2014-04-08
  • 2014-04-11
  • 1970-01-01
  • 2018-02-19
相关资源
最近更新 更多