OptimisticConcurrency未进行任何更改时的异常

时间:2015-08-19 18:54:52

标签: c# entity-framework entity-framework-6 optimistic-concurrency

我偶尔会在MVC Web应用程序中使用Entity Framework 6调用OptimisticConcurrency时收到SaveChanges()异常,即使我没有对此执行线程中的任何对象进行任何更改。当然可以在不同的线程/进程中进行更改。似乎不可能发生OptimisticConcurrency异常,但是,它会以某种频率发生。

var launchedSurvey = DB.Find<LaunchedSurvey>(id);
DB.SaveChanges(); // throws OptimisticConcurrencyException 

我调用SaveChanges即使没有任何更改只是作为测试发生,因为我在添加记录时收到了相同的异常,但是没有对现有对象进行任何更改...这似乎也不应该抛出{{1} }。

这是错误消息

OptimisticConcurrencyException

这是LaunchedSurvey的c-tor

System.Exception: TestSave Failed ---> System.Data.Entity.Infrastructure.DbUpdateException: SaveChangesAndReload caught exception and attempted to handle it => attempts:5
 ---> System.Data.Entity.Infrastructure.DbUpdateException: An error occurred while saving entities that do not expose foreign key properties for their relationships. The EntityEntries property will return null because a single entity cannot be identified as the source of the exception. Handling of exceptions while saving can be made easier by exposing foreign key properties in your entity types. See the InnerException for details. ---> System.Data.Entity.Core.OptimisticConcurrencyException: Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=472540 for information on understanding and handling optimistic concurrency exceptions.
   at 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.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)
   at System.Data.Entity.Core.Objects.ObjectContext.SaveChangesToStore(SaveOptions options, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction)
   at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)
   at System.Data.Entity.Core.Objects.ObjectContext.SaveChangesInternal(SaveOptions options, Boolean executeInExistingTransaction)
   at System.Data.Entity.Internal.InternalContext.SaveChanges()

非常感谢对此的任何见解!

2 个答案:

答案 0 :(得分:1)

在你的两行代码中......

var launchedSurvey = DB.Find<LaunchedSurvey>(id);
DB.SaveChanges(); 

...运行的唯一应用程序代码是属性设置器中的构造函数和代码。这就是为什么我要求查看构造函数(属性setter中的代码不太常见)。

当然我不知道映射了哪些属性,但构造函数显示了两个可能可存储的赋值:

WorkerSurveyStatisticAuto = new WorkerSurveyStatisticAuto();
WorkerSurveyStatisticManual = new WorkerSurveyStatisticManual();

如果映射了这些引用,即如果涉及的对象是映射实体,则在实现LaunchedSurvey对象时,EF 将不会再次设置它们。现在,当您保存对象时,EF将尝试将0分配给外键值。这可能是 -

  • 总是抛出一个FK约束异常,因为我不希望Id = 0的记录存在于数据库中
  • 抛出验证异常,因为新对象未处于有效状态。
  • 如果并发用户在获取和保存LaunchedSurvey对象之间的短时间内更新了任何引用的对象,则
  • 抛出一个乐观并发异常。

消息是:不要在实体构造函数中设置映射的引用属性。另见:EF codefirst : Should I initialize navigation properties?

答案 1 :(得分:0)

请注意,EF中的乐观并发处理在很大程度上依赖于查询返回的受影响行数来检测问题。因此,导致更新/插入/删除返回意外数量的受影响行的其他原因,也可能导致引发OptimisticConcurrencyException。

就我而言,我正在使用IGNORE_DUB_KEY=ON将重复的行插入表中。这使SQL Server在违反主键约束的情况下返回“受影响的0行”以及警告,而不是引发错误。