2012-05-02 77 views
4

如果用戶#1刪除了我們的Access 2007數據庫(SQL Server ODBC鏈接表)中的記錄,其他用戶可能會在該記錄中顯示#Deleted#(在數據表視圖窗體上) 。在某些情況下,這可能會導致問題,因爲我擁有在窗體當前事件上運行的代碼,並簡單地假定存在有效記錄(或新記錄)。如果當前記錄在訪問綁定表中被刪除

是否有任何可靠的方法來檢測當前記錄是否已被刪除?我想它包在像這樣的功能:

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

我發現在MSDN中的DAO參考RECORDSTATUS屬性,但該屬性出現如果記錄配置爲批量更新僅是有效的。當我嘗試檢查它的值時:運行時錯誤3251 - 此類對象不支持操作。

我實際上在一年或兩年前在另一個論壇上發佈了關於這個同樣的問題。給出的建議不工作:

  • DCOUNT()
  • 書籤和記錄的NOMATCH
  • 在PK或FK場
+0

好問題,但我不認爲它會適用於當前事件中的Requery。那會導致無限循環。但是,如果我確實檢測到刪除的記錄,那麼我確實需要重新查詢才能解決問題。 – HK1

+0

@ HK1這可能不會有什麼幫助,但我總是建議使用db服務器作爲避免使用DAO鏈接綁定表單的後端。與ADO一起運行任何查詢服務器端而不是本地服務器,並且爲表單提供未綁定的解決方案。 –

+0

感謝您的推薦。我傾向於使用ADO作爲最後的手段。如果DAO和ODBC做我需要的東西,我想我沒有看到需要改變。但是我意識到ADO通常被認爲更穩定和更強大。 – HK1

回答

3

對我來說,這看起來更像是檢查中#Deleted一個通用的應用程序設計監督,而不是一個簡單的解決方法。

如果您對重要地方的記錄可用性做出了假設,那麼您必須考慮到刪除記錄作爲數據主要(和有效)狀態的可能性。

這是可能的 - 但我認爲不太可能 - 你會找到解決方法,但我認爲你應該仔細看看你的整體設計本身。

解決這個問題,這可能是也可能不是你的情況是有用的,這取決於你的數據是如何包含與用戶訪問一些方法:

  • 只要不依賴於記錄是否存在如果你不能確定他們會在那裏。
    基本上,重做你的假設並修改你現有的代碼,以避免依賴強制存在的記錄。

  • 職責分離
    不允許不同的用戶對同一數據具有相同的創建/編輯/刪除權限。例如,採購訂單應該屬於創建它的用戶。不允許其他用戶分別刪除該訂單或其項目。不要實際刪除實體,僅允許用戶將其標記爲'已取消'或'過時',並由於歷史原因將其保留在數據庫中(或稍後清除)。

  • 或者,實際上不要刪除記錄,而是添加一個隱藏的布爾字段,以在用戶想要刪除它們時將其標記爲「已刪除」。然後,您可以每天晚上進行一些清理工作,並實際刪除標記的記錄。
    當然,您必須從查詢和表單等中排除這些「已刪除」記錄,但數據完整性將被保留。

  • 將報告和記錄列表設置爲只讀,以便用戶不能在任何地方將其刪除。例如,如果用戶可以查看採購訂單項目,則除非他們實際打開採購訂單明細表單,否則不允許他們刪除該數據。

  • 在本地緩存記錄,以便如果它們從後端數據庫中消失,它們仍會顯示給查看它們的用戶,直到它們刷新列表。
    這對於只讀報告通常很有用:將查詢結果加載到本地表中,並使用實時數據綁定該表而不是查詢。
    正在查看的數據可能會稍微陳舊,因爲它不會實時更新(因爲它本地緩存),但對於報告,通常可以(只需在窗體上提供「刷新」按鈕以允許用戶強制刷新)。

  • 使用各種鎖定選項(請參閱database optionsform 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代碼中查看從其他位置刪除記錄時發生Error 3167「記錄已刪除」的位置。
    一旦您知道它在代碼中的位置,就可以使用On Error 3167 Goto YourErrHandler來捕獲該錯誤,以便優雅地處理該特定錯誤(這將取決於您的表單的設計方式以及如何使用數據)。

  • 另一種選擇是使用全局錯誤處理程序進行訪問。
    我只知道vbWatchdog。它不是免費的,但它工作得非常好,並且很容易集成到應用程序中。
    此加載項集成在您的應用程序中,無需爲每個用戶單獨安裝。安裝完成後,您的應用程序將能夠捕捉到高級別的所有錯誤。因此,您將能夠捕捉到「記錄已刪除」錯誤並在一個地方處理它們。

+0

感謝您提供全面的解決方案和想法。我不確定我是否完全同意你寫的所有內容,但我認爲你的回答在解決問題方面做得很好。 – HK1

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(記錄中刪除),但是當試圖訪問值屬性時,我似乎只能得到上述三個錯誤。

如果您當前的事件較長,或者像這樣運行代碼的風險很大,您可以使用類似的技術,但在開始時故意引發錯誤(dummyvalue = SomeBoundControl.Value應該做到這一點)和然後將錯誤處理程序中的「Resume Next」更改爲「Exit Sub」。

0

如果記錄仍然存在,您可以檢查不是空白的字段

我使用一個日期更新或日期創建字段,它是默認值= Now()第一次打開表單時自動填充的。

由於它的值似乎如果記錄已經被刪除,以改變爲空字符串,我可以窗體本身上觸發

If Me.DateUpdated = "" Then 

(例如跳過關閉過程中的操作)。此檢查也可能從其他形式起作用。

相關問題