4

如果用户 #1 删除了 Access 2007 数据库(SQL Server ODBC 链接表)中的一条记录,其他用户可能会在该记录中显示 #Deleted#(在数据表视图表单上)。在某些情况下,这可能会导致问题,因为我有在表单的当前事件上运行的代码,并且只是假设存在有效记录(或新记录)。

有没有可靠的方法来检测当前记录是否已被删除?我想将它包装在这样的函数中:

Public Function IsRecordDeleted(ByRef r As DAO.Recordset)
   'what goes here?
End Function

我确实在 MSDN 的 DAO 参考中找到了 RecordStatus 属性,但该属性似乎仅在 RecordSet 配置为批量更新时才有效。当我尝试检查它的值时,我得到:运行时错误 3251 - 这种类型的对象不支持操作。

实际上,我在一两年前就在另一个论坛上发布过同样的问题。给出的建议不起作用:

  • 计数()
  • 记录集的书签和 NoMatch
  • 检查 PK 或 FK 字段中的#Deleted
4

3 回答 3

3

对我来说,这看起来更像是一个通用的应用程序设计疏忽,而不是一个具有简单解决方法的简单问题。

如果您对重要位置的记录可用性做出假设,那么您必须考虑将删除记录作为数据的主要(和有效)状态的可能性。

有可能——但我认为不太可能——你会找到一种解决方法,但我认为你应该仔细看看你的整体设计本身。

解决此问题的一些方法可能对您的情况有用,也可能没有用,具体取决于用户包含和访问您的数据的方式:

  • 如果您不能确定它们是否存在,请不要依赖记录的存在。
    基本上,重新设计您的假设并修改您现有的代码,以避免依赖于强制存在的记录。

  • 职责分离
    不允许不同用户对相同数据拥有相同的创建/编辑/删除权限。例如,采购订单应该属于创建它的用户。不允许其他用户单独删除该订单或其商品。

  • 不要实际删除实体,只允许用户将其标记为“已取消”或“已过时”并出于历史原因将其保留在数据库中(或稍后清除它们)。

  • 或者,实际上不要删除记录,而是添加一个隐藏的布尔字段以在用户想要删除它们时将它们标记为“已删除”。然后你可以做一些清理工作,比如说每晚,然后实际删除标记的记录。
    当然,您必须从您的查询和表单等中排除这些“已删除”的记录,但将保留数据完整性。

  • 将报告和记录列表设为只读,这样用户就不能随便在任何地方删除它们。例如,如果用户可以查看采购订单项目,则不允许他们删除该数据,除非他们实际打开采购订单详细信息表单。

  • 在本地缓存记录,以便如果它们从后端数据库中消失,它们仍会显示给查看它们的用户,直到他们刷新列表。
    这对于只读报告通常很有用:将查询结果加载到本地表中并绑定该表,而不是使用实时数据进行查询。
    正在查看的数据可能有点陈旧,因为它不会实时更新(因为它是在本地缓存的),但对于报告,它通常没问题(只需在表单上提供一个“刷新”按钮以允许用户强制刷新) .

  • 尝试各种锁定选项(请参阅数据库选项表单记录锁定)以在其他人访问记录时禁止删除记录。

  • 管理您自己的锁定方案。
    作为最后的手段,您可以在“LockingStatus”表中记录当前正在被其他人查看或编辑的 ID 和记录。例如:

    Table: LockStatus
    Field: LockNature:   Whether the record is being Edited or Viewed
    Field: LockedTable:  Name of the table of the record being locked
    Field: LockedRecord: ID of the record being locked
    Field: User:         Name of the user holding the lock
    Field: LockTime:     DateTime of the lock creation, so you can detect 
                         and remove stale locks
    

    当用户查看或编辑记录时,首先检查表中是否存在该记录的现有条目。如果有,则告诉用户他们无法执行该操作,因为其他人正在查看数据。如果没有现有条目,则添加一个,允许编辑,并在编辑完成后删除记录。
    这充满了复杂性,因为您需要跟踪用户何时移动到另一条记录,以便您可以解锁前一条记录,如果您不小心,您最终可能会遇到很多过时的锁,但之前已经完成.

  • 如果您仍然真的想规避删除记录问题,请查看在您的 VBA 代码中,当您从另一个位置删除记录时出现错误 3167“记录已删除”。
    一旦你知道它在你的代码中出现的位置,捕获那个错误On Error 3167 Goto YourErrHandler以优雅地处理那个特定的错误(这实际上取决于你的表单是如何设计的以及你如何使用你的数据)。

  • 另一种选择是使用全局错误处理程序进行访问。
    我只知道vbWatchdog。它不是免费的,但效果非常好,并且很容易集成到应用程序中。
    此加载项集成在您的应用程序中,无需为每个用户单独安装。设置完成后,您的应用程序将能够在高级别捕获所有错误。因此,您将能够捕获“记录已删除”错误并在一处处理它们。

于 2012-05-03T03:27:18.210 回答
0

我通过 Form_Current 事件中的代码遇到了同样的事情,并在这里结束。

错误处理是最好的(也是唯一的?)方法。为了我自己的目的,我只是在当前事件中运行了一些简单的控件更新,所以我编写了错误处理程序来从我得到的错误中恢复

Private Sub Form_Current()
    On Error GoTo handler

    'do intended things here, e.g. attempt to access the value
    'of a control even though the record may be deleted  

    Exit Sub

  handler:
    If Err.Number = 438 Or Err.Number = 13 Then 
        'type mismatch, probably due to deleted record, skip it
        Resume Next
    ElseIf Err.Number = 3167 Then 
        'record is deleted, skip it
        Resume Next
    Else
        Err.Raise Err.Number, Err.Source, Err.Description
    End If
End Sub

我没有可靠地得到 3167(记录已删除),但是在尝试访问值属性时,我似乎只得到了上面困住的 3 个错误。

如果您当前的事件较长,或者运行这样的代码有风险,您可以使用类似的技术,但故意在方法开始时引发错误(dummyvalue = SomeBoundControl.Value 应该可以解决问题),然后更改“将错误处理程序中的 Next 恢复到“Exit Sub”。

于 2012-10-31T02:02:19.963 回答
0

您可以检查一个非空白字段以确定该记录是否仍然存在。

我使用日期更新或创建日期字段,一旦第一次打开表单,默认值 =Now() 就会自动填充该字段。

由于如果记录已被删除,它的值似乎会变为空字符串,我可以触发

If Me.DateUpdated = "" Then

在表单本身上(例如跳过关闭过程中的操作)。此检查也可能适用于其他形式。

于 2016-02-29T23:19:39.250 回答