能否对EF Core ChangeTracker状态快照并按需重置?
EF Core:能否为ChangeTracker生成状态快照并重置?
请问是否可以对EF Core的ChangeTracker当前状态生成快照,并在需要时重置至该快照状态?
假设我们希望实现如下代码逻辑:
public async Task ExecuteTransactionAsync(DbContext context) { var executionStrategy = new SqlServerRetryingExecutionStrategy(context); var retries = 0; var snapshot = null; await executionStrategy.ExecuteAsync(async () => { var txOptions = new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }; using var transaction = new TransactionScope(TransactionScopeOption.RequiresNew, txOptions, TransactionScopeAsyncFlowOption.Enabled) if (retries > 0 && snapshot != null) { // 该方法实际不存在 context.ChangeTracker.ResetToSnapshot(snapshot); } // 该方法实际不存在 var snapshot = context.ChangeTracker.TakeSnapshot(); retries += 1; // 假设我们在context上执行插入操作 context.DoInsert(); await context.SaveChangesAsync(false); // 假设我们在context上执行更新操作 context.DoUpdate(); // 假设第一次调用SaveChanges失败,事务会重试 await context.SaveChangesAsync(false); transaction.Complete(); } }
该功能的实用性
在结合ChangeTracker和重试事务使用时,数据库会在重试间隙回滚事务,但ChangeTracker没有对应的回滚机制。使用SaveChanges(false)虽能在重试间保留ChangeTracker状态,但会引发以下问题:
- 首次运行插入实体,重试时会再次添加实体,最终数据库插入两个实体,与预期不符;
- 若对实体属性使用
+=/-=操作(比如Price初始为10,执行Price -=2),重试后Price会变为6,而非预期的8。
因此,能够将ChangeTracker重置至某一时刻的状态极为必要。
以下是未使用快照重置时的问题示例:
public async Task ExecuteTransactionAsync(DbContext context) { var executionStrategy = new SqlServerRetryingExecutionStrategy(context); await executionStrategy.ExecuteAsync(async () => { var txOptions = new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }; using var transaction = new TransactionScope(TransactionScopeOption.RequiresNew, txOptions, TransactionScopeAsyncFlowOption.Enabled) // 第一次重试时,ChangeTracker中已经添加了一个新实体 // DoInsert会再添加一个,最终会有两个新实体,与预期的一个不符 context.DoInsert(); await context.SaveChangesAsync(false); context.DoUpdate(); // 假设第一次调用SaveChanges失败,事务会重试 await context.SaveChangesAsync(false); transaction.Complete(); } }
内容的提问来源于stack exchange,提问作者mcvyty
相关产品推荐
相关产品推荐

