DbContext查询(Get)正常但更新(Update)失效,求原因排查
1. 事务未提交导致修改被回滚
你的Repository继承了UnitOfWork,而UnitOfWork的构造函数会自动开启一个数据库事务:
public UnitOfWork(DbContext context) { _context = context ?? throw new ArgumentNullException(nameof(context)); _transaction = _context.Database.CurrentTransaction ?? _context.Database.BeginTransaction(); }
但你在更新流程中调用的是Repository的SaveAsync方法,它仅执行了_context.SaveChangesAsync(),并没有触发UnitOfWork的Commit方法来提交事务:
public async Task<int> SaveAsync() { return await _context.SaveChangesAsync(); }
在EF Core中,事务未提交时,SaveChangesAsync的修改仅存在于事务日志中,不会持久化到数据库。当UnitOfWork实例被销毁时,未提交的事务会被自动回滚,最终导致更新操作失效。
2. Repository与UnitOfWork的职责耦合错误
Repository继承UnitOfWork的设计违背了单一职责原则:
Repository的职责是封装单实体的数据访问操作UnitOfWork的职责是管理多个Repository的事务一致性,确保操作原子性
这种继承关系会导致每个Repository实例都拥有独立的事务,无法实现多操作的事务统一管理,同时也会引发上下文生命周期的混乱。
3. 异步Dispose方法实现错误
UnitOfWork的Dispose(bool disposing)使用了async void,这是异步编程中的错误实践:
protected virtual async void Dispose(bool disposing) { if (disposing) { await _context.DisposeAsync(); _transaction.Dispose(); } }
async void方法无法被等待,会导致上下文和事务的释放操作无法正确完成,可能引发资源泄漏或上下文提前销毁的问题。正确的做法是实现IAsyncDisposable接口,使用异步释放模式。
4. 冗余的Update调用(非直接原因,但需优化)
在Controller中,你通过GetByIdentityNumber获取的实体处于DbContext的跟踪状态,当你修改实体属性时,EF Core会自动将其标记为Modified状态,无需额外调用Update方法。冗余的Update调用不仅没有必要,还可能覆盖实体的跟踪状态。
调整Repository与UnitOfWork的关系
- 让
UnitOfWork包含多个Repository实例,而不是让Repository继承UnitOfWork - 示例结构:
public class UnitOfWork : IUnitOfWork { private readonly DbContext _context; private IDbContextTransaction _transaction; // 按需添加Repository实例 public IResponsibleDal ResponsibleDal { get; } public UnitOfWork(DbContext context, IResponsibleDal responsibleDal) { _context = context; ResponsibleDal = responsibleDal; } // 事务管理逻辑... }
- 让
确保事务正确提交
- 移除
Repository中的SaveAsync方法,统一通过UnitOfWork的Commit方法提交事务和保存更改 - 在Controller中完成操作后调用
UnitOfWork.Commit()
- 移除
修复异步Dispose实现
- 实现
IAsyncDisposable接口:public class UnitOfWork : IUnitOfWork, IAsyncDisposable { // ...其他代码 public async ValueTask DisposeAsync() { await DisposeAsyncCore(); GC.SuppressFinalize(this); } protected virtual async ValueTask DisposeAsyncCore() { if (_transaction != null) { await _transaction.DisposeAsync(); } await _context.DisposeAsync(); } }
- 实现
优化Controller中的更新逻辑
- 移除冗余的
Update调用,直接修改跟踪实体的属性后提交事务:var entity = _mainBus.ResponsibleBus.GetByIdentityNumber(model.UserName); if (entity is not null) { entity.ThemeSettings = model.Theme; // 调用UnitOfWork的Commit方法提交事务 await _unitOfWork.Commit(); HttpContext.Session.SetString("Theme", model.Theme.ToString()); }
- 移除冗余的
调整依赖注入配置
- 将
UnitOfWork注册为Scoped(与DbContext生命周期一致),确保每个请求使用同一个事务上下文 - 避免不必要的
Lazy包装,简化DI配置
- 将
内容的提问来源于stack exchange,提问作者Musa AKYUZ

