如果用户#1删除Access 2007数据库(SQL Server ODBC链接表)中的记录,则其他用户可能会在该记录中显示#Deleted#(在数据表视图表单上)。在某些情况下,这可能会导致问题,因为我的代码在Form的当前事件上运行,并且只是假设存在有效记录(或新记录)。
有没有可靠的方法来检测当前记录是否已被删除?我想把它包装成这样的函数:
Public Function IsRecordDeleted(ByRef r As DAO.Recordset)
'what goes here?
End Function
我确实在MSDN的DAO引用中找到了RecordStatus属性,但该属性似乎仅在RecordSet配置为批量更新时才有效。当我尝试检查它的值时,我得到:运行时错误3251 - 此类对象不支持操作。
我实际上在一年或两年前在另一个论坛上发布了同样的问题。给出的建议不起作用:
答案 0 :(得分:3)
对我来说,这看起来更像是一般的应用程序设计疏忽,而不是一个简单的解决方案。
如果您对重要地方的记录可用性做出假设,那么您必须考虑删除记录作为数据主要(和有效)状态的可能性。
有可能 - 但我认为不太可能 - 你会找到一个解决方法,但我认为你应该仔细看看你的整体设计本身。
解决问题的一些方法,根据您的数据如何被用户包含和访问,可能会或可能不会对您有用:
如果你不能确定它们会在那里,那么就不要依赖于记录的存在 基本上,修改您的假设并修改现有代码,以避免依赖强制存在的记录。
责任分离
不允许不同的用户对相同的数据具有相同的创建/编辑/删除权限。例如,采购订单应属于创建订单的用户。不允许其他用户单独删除该订单或其项目。
实际上不要删除实体,只是允许用户将其标记为“已取消”或“已过时”,并将其保存在数据库中,这是出于历史原因(或稍后清除它们)。
< / LI>或者,不要实际删除记录,但添加隐藏的布尔字段,以便在用户想要删除它们时将其标记为“已删除”。然后你可以做一些清理工作,比如每晚,然后删除标记的记录 当然,您必须从查询和表单等中排除这些“已删除”记录,但数据完整性将被保留。
将报告和记录列表设为只读,这样用户就无法在任何地方删除它们。例如,如果用户可以查看采购订单项目,则不要允许他们删除该数据,除非他们实际打开采购订单详细信息表单。
在本地缓存记录,这样如果它们从后端数据库中消失,它们仍会显示给查看它们的用户,直到刷新列表为止。
这对于只读报告通常很有用:将查询结果加载到本地表中,并使用实时数据绑定该表而不是查询。
正在查看的数据可能会稍微陈旧,因为它不会实时更新(因为它在本地缓存)但是对于报告,通常都可以(只需在表单上提供“刷新”按钮以允许用户强制刷新)
尝试使用各种锁定选项(请参阅database options和form record locking),以禁止在其他人访问记录时删除记录。
管理您自己的锁定方案 作为最后的手段,您可以在“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。它不是免费的,但它工作得非常好,并且很容易集成到应用程序中 此加载项集成在您的应用程序中,无需为每个用户单独安装。设置完成后,您的应用程序将能够捕获高级别的所有错误。因此,您将能够捕获“记录已删除”错误并在一个地方处理它们。
答案 1 :(得分: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应该做的伎俩)然后将错误处理程序中的“Resume Next”更改为“Exit Sub”。
答案 2 :(得分:0)
如果记录仍然存在,您可以检查非空白字段。
我使用更新日期或日期创建字段,首次打开表单时,默认值= Now()会自动填充。
如果记录被删除,它的值似乎变为空字符串,我可以触发
If Me.DateUpdated = "" Then
表单本身上的(例如,跳过结束程序中的操作)。此检查也可能适用于其他形式。