2015-11-13 33 views
2

我讀過幾篇有關可能導致dbUpdateConcurrencyException的事情的問題和文章,但他們中的任何一篇似乎都與我的代碼中發生的事情有關。我對我的CRUD操作進行了簡單的功能測試,這些操作使用Entity Framework 6.0加載後簡單刪除時出現dbUpdateConcurrencyException

我的[TestInitialize]插入了一些數據,我的[TestCleanup]刪除了相同的數據。這適用於我所有的測試,除了刪除記錄的測試外。當這個測試的清理被調用時,它會拋出一個dbUpdateConcurrencyException

我的測試清理方法僅僅是這樣的:

var contracts = this.Context.Contract 
     .Where(c => c.EntryUserID == "FunctionalTests.TestData").ToList(); 
    this.Context.Contract.RemoveRange(contracts); 

    this.Context.SaveChanges(); 

    var customers = this.Context.Customer 
     .Where(c => c.EntryUserID == "FunctionalTests.TestData").ToList(); 
    this.Context.Customer.RemoveRange(customers); 

    this.Context.SaveChanges(); //This throws dbUpdateConcurrencyException?? 

運行之前失敗從Context.Contract刪除一條記錄測試。一對夫婦奇怪的事情:

  • Context.Contract的清理工作得很好。這是Context.Customer的打破,即使Customer.Contract是在測試過程中被刪除的。
  • 我試圖刪除它們之前立即加載要刪除的實體。它們不可能在加載和嘗試刪除之間進行修改。我的理解是,當一個實體在加載和嘗試刪除之間被修改時,會發生這種異常。

Contract確實有一個外鍵到CustomerId。我猜這是相關的;刪除合同將改變實體Customer,因爲Customer實體具有一系列合同屬性。但是,我再次在之後加載新客戶我刪除了合同;所以它們是而不是在加載和刪除之間被修改。

我試過一次刪除一個項目而不是用RemoveRange();同樣的錯誤發生在第一次刪除。在嘗試刪除Customer之前,我已嘗試在特定的Customer實體上調用Reload();相同的結果。

另請注意,對於不刪除合同的所有其他測試,此工作正常。因此,在刪除客戶之前刪除所有合同通常可以正常工作。只有在刪除清理中的其他合同之前刪除了單個合同之後。

這是完全錯誤信息/堆棧跟蹤:

System.Data.Entity.Infrastructure.DbUpdateConcurrencyException:System.Data.Entity.Infrastructure.DbUpdateConcurrencyException:商店更新,插入或刪除語句的影響意外的行數(0)。自實體加載後,實體可能已被修改或刪除。有關理解和處理樂觀併發異常的信息,請參閱http://go.microsoft.com/fwlink/?LinkId=472540。 ---> System.Data.Entity.Core.OptimisticConcurrencyException:存儲更新,插入或刪除語句會影響意外數量的行(0)。自實體加載後,實體可能已被修改或刪除。見http://go.microsoft.com/fwlink/?LinkId=472540的信息,理解和處理樂觀併發異常.. 結果堆棧跟蹤:在System.Data.Entity.Internal.InternalContext.SaveChanges
() 在System.Data.Entity.Internal.LazyInternalContext。調用SaveChanges() 在System.Data.Entity.DbContext.SaveChanges()

內部異常具有完全相同的類型和消息,與該堆棧跟蹤:

在System.Data.Entity的。 Core.Mapping.Update.Internal.UpdateTranslator.ValidateRowsAffected(Int64 rowsAffected,UpdateCommand source) at System.Data.Entity.Core.Mapping.Update.Internal.UpdateTranslator.Update() at System.Data.Entity.Core.EntityClient .Internal.EntityAdapter.b__2(UpdateTranslator ut) at System.Data.Entity.Core.EntityClient.Internal.EntityAdapter.Update [T](T noChangesResult,函數功能2 updateFunction) at System.Data.Entity.Core.EntityClient.Internal.EntityAdapter.Update() at System.Data.Entity.Core.Objects.ObjectContext.<SaveChangesToStore>b__35() at System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func 1 FUNC,IDbExecutionStrategy executionStrategy,布爾startLocalTransaction,布爾releaseConnectionOnSuccess) 在System.Data.Entity.Core.Objects.ObjectContext.SaveChangesToStore(SaveOptions選項,IDbExecutionStrategy executionStrategy,布爾startLocalTransaction) 在System.Data.Entity.Core .Objects.ObjectContext。 <> c__DisplayClass2a.b__27() at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute [TResult](Func`1 operation) at System.Data.Entity.Core.Objects.ObjectContext.SaveChangesInternal(SaveOptions options,Boolean executeInExistingTransaction ) 處System.Data.Entity.Internal.InternalContext.SaveChanges System.Data.Entity.Core.Objects.ObjectContext.SaveChanges(SaveOptions選項) ()

更新

我能夠通過傳遞來讓它工作/解決它,我在我的數據設置/拆卸中使用了正在測試的方法。換句話說,這個錯誤似乎是因爲有一個DbContext被用於測試設置/拆卸,而另一個DbContext被用於被測試的代碼。

但是,這並沒有真正回答我的任何問題。我寧願不必傳遞我的DbContext以確保它是相同的;有沒有一種方法可以告訴我的上下文從實際數據庫刷新/加載,而不僅僅是使用它所知道的內容?而且,這並不能解釋爲什麼刪除合同會正常工作,而且只能刪除客戶。

+0

爲什麼在一個地方使用兩次SaveChanges()調用?我知道它不相關。順便說一句你有沒有檢查兩個DbContext實例的哈希碼? – CodeNotFound

+0

@CodeNotFound我插入了另一個SaveChanges()以確認問題與試圖在合同被刪除之前刪除客戶沒有關係。最初它只有一個SaveChanges()。 – GendoIkari

+0

請問您可以在dbUpdateConcurrencyException中向我們顯示確切的消息嗎?我知道這是一個併發異常,但有時你可以在InnerException消息中擁有大量信息。 – CodeNotFound

回答

0

此錯誤是由於測試設置和拆卸使用的DBContext在測試設置運行時正在加載引起的。不同的上下文使數據庫在安裝和拆卸之間發生變化,並且由於第一個上下文在安裝過程中被加載,它基於數據庫的「舊」版本,即運行測試之前的版本。

解決方法是不要使用與安裝程序所使用的相同的DBContext。拆卸應該加載它自己的新的DBContext,以便它會根據最新的數據加載。

我以爲重要的是數據在從數據庫加載的時候的狀態。但顯然重要的是DBContext加載時的數據狀態。