未进行任何更改时的 OptimisticConcurrency 异常
OptimisticConcurrency Exception when no changes made
在 MVC Web 应用程序中使用 Entity Framework 6 调用 SaveChanges()
时,我偶尔会收到 OptimisticConcurrency
异常,即使我没有对该执行线程中的任何对象进行任何更改。当然有可能在不同的 thread/processs 中进行了更改。 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>();
}
非常感谢任何对此的见解!
在你的两行代码中...
var launchedSurvey = DB.Find<LaunchedSurvey>(id);
DB.SaveChanges();
...运行的唯一 application 代码是 属性 setter 中的构造函数和代码。这就是为什么我要求查看构造函数(属性 setter 中的代码不太常见)。
当然我不知道映射了哪些属性,但是构造函数揭示了两个可能的 storable 赋值:
WorkerSurveyStatisticAuto = new WorkerSurveyStatisticAuto();
WorkerSurveyStatisticManual = new WorkerSurveyStatisticManual();
如果这些引用被映射,即如果涉及的对象是映射的实体,EF 不会在 LaunchedSurvey
对象具体化时再次设置它们。现在,当您保存对象时,EF 将尝试将 0 分配给外键值。这可能是 -
- 总是抛出 FK 约束异常,因为我不希望 Id = 0 的记录出现在数据库中
- 抛出验证异常,因为新对象未处于有效状态。
- 如果并发用户在获取和保存
LaunchedSurvey
对象之间的短时间内更新了任何引用的对象,则抛出开放式并发异常。
信息是:不要在实体构造函数中设置映射引用属性。另见:EF codefirst : Should I initialize navigation properties?
请注意,EF 中的乐观并发处理在很大程度上依赖于受影响的行数 return 通过查询来检测问题。因此,导致 update/insert/delete 到 return 意外数量的受影响行的其他原因也可能导致抛出 OptimisticConcurrencyException。
在我的例子中,我将重复的行插入到 table 和 IGNORE_DUB_KEY=ON
中。这使得 SQL 服务器 return “0 行受影响”并在违反主键约束时发出警告,而不是抛出错误。
在 MVC Web 应用程序中使用 Entity Framework 6 调用 SaveChanges()
时,我偶尔会收到 OptimisticConcurrency
异常,即使我没有对该执行线程中的任何对象进行任何更改。当然有可能在不同的 thread/processs 中进行了更改。 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>();
}
非常感谢任何对此的见解!
在你的两行代码中...
var launchedSurvey = DB.Find<LaunchedSurvey>(id);
DB.SaveChanges();
...运行的唯一 application 代码是 属性 setter 中的构造函数和代码。这就是为什么我要求查看构造函数(属性 setter 中的代码不太常见)。
当然我不知道映射了哪些属性,但是构造函数揭示了两个可能的 storable 赋值:
WorkerSurveyStatisticAuto = new WorkerSurveyStatisticAuto();
WorkerSurveyStatisticManual = new WorkerSurveyStatisticManual();
如果这些引用被映射,即如果涉及的对象是映射的实体,EF 不会在 LaunchedSurvey
对象具体化时再次设置它们。现在,当您保存对象时,EF 将尝试将 0 分配给外键值。这可能是 -
- 总是抛出 FK 约束异常,因为我不希望 Id = 0 的记录出现在数据库中
- 抛出验证异常,因为新对象未处于有效状态。
- 如果并发用户在获取和保存
LaunchedSurvey
对象之间的短时间内更新了任何引用的对象,则抛出开放式并发异常。
信息是:不要在实体构造函数中设置映射引用属性。另见:EF codefirst : Should I initialize navigation properties?
请注意,EF 中的乐观并发处理在很大程度上依赖于受影响的行数 return 通过查询来检测问题。因此,导致 update/insert/delete 到 return 意外数量的受影响行的其他原因也可能导致抛出 OptimisticConcurrencyException。
在我的例子中,我将重复的行插入到 table 和 IGNORE_DUB_KEY=ON
中。这使得 SQL 服务器 return “0 行受影响”并在违反主键约束时发出警告,而不是抛出错误。