EF6存儲錯誤的解決

最近使用EF的時候,前端程序員反應數據庫運行一旦時間會發生一個存儲錯誤,查看日誌後,發現是EF拋出的異常,具體異常消息爲“The object cannot be deleted because it was not found in the ObjectStateManager”

經過調試,發現是對EF6中的DbSet調用RemoveRange函數時拋出的異常。讓人很頭痛,也沒有精力去研究EF的源代碼來準確的定位錯誤產生的原因,然後ObjectStateManager又是EF中的什麼東西?看似是一個棘手,一時無法解決的問題。

項目馬上就要進行上線更新,所以靜下心來分析。仔細閱讀錯誤日誌,可以發現,該異常應該是在Delete某個object時產生的,而且我們調試下來也是在RemoveRange這個函數,那麼可以假定應該是我們調用該函數時,傳遞的,要刪除的記錄數據出了問題。而且是因爲找不到要刪除的數據才報的錯。

斷點,監視數據,發現我們傳遞進去要刪除的數據有4條,查看了具體的數據後,發現4條數據的值居然一模一樣。那馬上聯想到,我們在業務邏輯上存在錯誤,是否反覆將同一記錄多次添加到待刪除的隊列中了。經過一番排查,確實發現了業務邏輯上存在問題,有將同一記錄多次刪除的情況,修改。

運行後,錯誤依舊。這下又迷茫了,還是繼續斷點調試,發現這時RemoveRange中並沒有重複的數據記錄。那爲何還是會報這個異常呢?在對比異常消息,作出進一步的假設,會不會說,這條待刪除的數據,數據庫中本身就沒有?

我們拋出異常的業務邏輯的行爲,是一段處理玩家申請的邏輯。在申請到來時保存申請記錄,一旦申請處理後,刪除該記錄。服務器定時存儲數據庫。這時突然聯想到了兩點,首先EF的對數據庫的操作,其本質還是執行的SQL語句,其次,其對數據庫的改變,必須經過SaveChanges才能最終反應在數據庫中。我們的業務邏輯,在保存申請記錄時,調用的DbSet的Add函數,刪除時調用DbSet的Remove函數,然後纔是SaveChanges。如果DbSet是普通的集合,這沒有問題。但是如果Add,Remove其最終執行的是Sql語句的話,當Add執行後,還沒有SaveChanges(相當於Sql語句中Commit),那麼這條記錄可能並沒有真正存在於數據庫中,那麼下面的Remove自然就找不到該記錄,從而產生異常。

所以從我們的業務邏輯看,如果處理完申請,該記錄被刪除,其實相當於是取消了剛纔保存的記錄。也就是不對該記錄進行Add操作

總結

對DbSet進行操作時,如果是操作數據庫已有的記錄,那麼沒有任何問題。而如果是操作數據庫還沒有的數據,只是緩衝到DbSet中的數據,我們要注意,如果是刪除操作,實際是撤銷前面的添加操作,如果是修改操作,要找到先前添加到DbSet緩存中的記錄進行操作,而不是另起一條操作記錄。要明確,沒有SaveChanges時,這些數據在數據庫中並不存在

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章