未做任何更改时出现OptimisticConcurrency异常

本文关键字:OptimisticConcurrency 异常 任何更 | 更新日期: 2023-09-27 18:08:51

在MVC web应用程序中使用实体框架6调用SaveChanges()时,我偶尔会收到OptimisticConcurrency异常,即使我没有更改此执行线程内的任何对象。当然,在不同的线程/进程中进行更改是可能的。OptimisticConcurrency异常似乎是不可能发生的,但是,唉,它经常发生。

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

我调用SaveChanges,即使没有变化发生简单的测试,因为当添加记录时,我收到了相同的异常,但没有对现有对象发生任何变化……这似乎也不应该抛出OptimisticConcurrencyException

这是错误信息

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()

这是LaunchedSurvey的c-tor

public LaunchedSurvey()
{
    CreationTime = DateTime.UtcNow;
    WorkerLaunchedSurveys = new Collection<WorkerLaunchedSurvey>();
    WorkerQualificationRequests = new Collection<WorkerQualificationRequest>();
    _remainingDemographic = new DateTime(1900, 1, 1);
    MinimumPercent = 0.10;
    ExcludeList = new List<LaunchedSurvey>();
    IncludeList = new List<LaunchedSurvey>();
    ScreenedWorkers = new List<ScreenedWorker>();
    EmailMessages = new List<EmailMessage>();
    AssignmentsPendingWorkers = new HashSet<AssignmentsPendingWorker>();
    ExcludedWorkersManual = new List<AmazonWorkerExcluded>();
    IncludedWorkersManual = new List<AmazonWorkerIncluded>();
    PendingWorkersQualificationsUnknown = new List<AmazonWorkerPending>();
    Tags = new List<Tag>();
    ManualQualificationTypeIdList = new List<QualificationType>();
    WorkerSurveyStatisticAuto = new WorkerSurveyStatisticAuto();
    WorkerSurveyStatisticManual = new WorkerSurveyStatisticManual();
    WorkerUniqueIdentifierList = new List<WorkerUniqueIdentifier>();
}

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

未做任何更改时出现OptimisticConcurrency异常

在你的两行代码中…

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

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

当然,我不知道映射了哪些属性,但是构造函数显示了两个可能的可存储的赋值:
WorkerSurveyStatisticAuto = new WorkerSurveyStatisticAuto();
WorkerSurveyStatisticManual = new WorkerSurveyStatisticManual();

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

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

消息是:不要在实体构造函数中设置映射的引用属性。参见:EF codefirst:我应该初始化导航属性吗?

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

在我的例子中,我插入一个重复行到一个表与IGNORE_DUB_KEY=ON。这使得SQL服务器在违反主键约束时返回"受影响的0行"并发出警告,而不是抛出错误。

相关文章:
  • 没有找到相关文章