为什么我在回滚后在 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 原始值。
当然有一个简单的补救方法:使用新的上下文进行第二次更新。
我的 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 原始值。
当然有一个简单的补救方法:使用新的上下文进行第二次更新。