为什么我在回滚后在 SaveChanges 上收到 DbUpdateConcurrencyException

Why am I getting a DbUpdateConcurrencyException on SaveChanges after a Rollback

我的 EF Core 3.1 代码分解为以下示例。更改某些实体 (MyData=1) 后,我在出错后回滚数据库,并且需要在回滚 (MyData=2) 后更新同一实体。而且,我在第二个 SaveChanges 上收到 DbUpdateConcurrencyException。

为什么,我得到这个例外?我怎样才能更改我的代码来解决问题?

谢谢大家

using var MyTransaction = MyContext.Database.BeginTransaction () ;

CMyEntity  MyEntity = GetMyEntityFromDatabase () ;
MyEntity.MyData = 1 ;
MyContext.SaveChanges () ;

MyTransaction.Rollback () ;

MyEntity = GetMyEntityFromDatabase () ;
MyEntity.MyData = 2 ;
MyContext.SaveChanges () ;

这是因为上下文在重新读取实体时从不重置并发标记的原始值。

假设 MyEntity 有一个 Rowversion 属性 作为并发令牌。

第一个 SaveChanges 递增 Rowversion 并且 EF 在更新语句后从数据库中读取新值。这个新值作为新的当前值 原始值存储在更改跟踪器中。你可以通过检查看到...

MyContext.Entry(MyEntity).Property(x => x.RowVersion).OriginalValue
MyContext.Entry(MyEntity).Property(x => x.RowVersion).CurrentValue

您还会看到,第二个 GetMyEntityFromDatabase 调用不会更改这些缓存值,即使事务已回滚并且数据库中的值已还原。事实上,EF 并不知道正在回滚的事务。

这就是为什么您在第二次 SaveChanges 调用时出现此并发异常的原因。 UPDATE 语句包含类似于 WHERE ... AND [RowVersion] = @p2; 的内容。但是 @p2 不是数据库中的 original 原始值。

当然有一个简单的补救方法:使用新的上下文进行第二次更新。