【发布时间】:2015-11-13 16:52:51
【问题描述】:
我已经阅读了一些关于可能导致dbUpdateConcurrencyException 的问题的问题和文章,但它们似乎都与我的代码中发生的事情无关。我对使用 Entity Framework 6.0 的 CRUD 操作进行了简单的功能测试。
我的[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的清理工作正常。尽管Customer.Contract是在测试期间被删除的内容,但对Context.Customer的清理是破坏性的。 - 我正在加载要删除的实体,然后再尝试删除它们。它们不可能在加载和尝试删除之间被修改。我的理解是,当实体在加载和尝试删除之间被修改时会发生此异常。
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 源) 在 System.Data.Entity.Core.Mapping.Update.Internal.UpdateTranslator.Update() 在 System.Data.Entity.Core.EntityClient.Internal.EntityAdapter.b__2(UpdateTranslator ut) 在 System.Data.Entity.Core.EntityClient.Internal.EntityAdapter.Update[T](T noChangesResult, Func
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](Func1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess) 在 System.Data.Entity.Core.Objects.ObjectContext.SaveChangesToStore(SaveOptions 选项,IDbExecutionStrategy executionStrategy,布尔 startLocalTransaction) 在 System.Data.Entity.Core.Objects.ObjectContext.c__DisplayClass2a.b__27() 在 System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 操作) 在 System.Data.Entity.Core.Objects.ObjectContext.SaveChangesInternal(SaveOptions 选项,布尔型 executeInExistingTransaction) 在 System.Data.Entity.Core.Objects.ObjectContext.SaveChanges(SaveOptions 选项) 在 System.Data.Entity.Internal.InternalContext.SaveChanges()
更新
通过将我在数据设置/拆卸中使用的DbContext 传递给正在测试的方法,我能够让它工作/解决它。换句话说,错误似乎是因为有一个DbContext 用于测试设置/拆卸,而另一个DbContext 用于正在测试的代码。
但是,这并不能真正回答我的任何问题。我宁愿不必传递我的DbContext 以确保它是相同的;有没有办法告诉我的上下文从实际数据库中刷新/加载,而不仅仅是使用它知道的内容?而且,这根本无法解释为什么删除合同会正常工作,并且只会在删除客户时失败。
【问题讨论】:
-
为什么在一个地方使用两次 SaveChanges() 调用?我知道这不相关。顺便说一句,您是否检查了两个 DbContext 实例的哈希码?
-
@CodeNotFound 我插入了另一个 SaveChanges() 以确认该问题与在删除合同之前尝试删除客户无关;最初它只有一个 SaveChanges()。
-
您能告诉我们dbUpdateConcurrencyException 中的确切消息吗?我知道这是一个并发异常,但有时您可以在 InnerException 消息中包含很多信息。
-
@CodeNotFound,我用完整的错误和堆栈跟踪更新了问题。
-
@GendoIkari 你能通过将
DbContext.Configuration.ProxyCreationEnabled设置为false 来关闭代理创建并报告结果吗?
标签: c# .net entity-framework concurrency entity-framework-6