访问DbContext触发System.ObjectDisposedException异常,求问题排查
问题分析与修复方案
核心问题:异步Lambda在ForEach中导致上下文被提前释放
你使用pOrders.ForEach(async po => { ... })时,这个异步Lambda属于async void类型方法,而List.ForEach根本不会等待这类异步方法执行完成。外层代码会继续向下执行,当你的异步操作还在处理时,DI容器可能已经将_dbContext回收释放,此时异步代码再访问_dbContext就会触发ObjectDisposedException。
其他潜在问题
taskFile可能为null,直接访问taskFile.Id会抛出空引用异常- 代码中的
jtaskFilesExt是笔误,应为taskFilesExt - 所有实体修改后未调用
_dbContext.SaveChangesAsync(),修改不会持久化到数据库
修复后的代码
把ForEach替换为普通foreach循环,用await等待每个异步操作完成,同时处理空引用问题,最后保存更改:
var pOrders = await _dbContext.POrders.Where(x => x.ShipId == data.shipNumber).ToListAsync(); foreach (var po in pOrders) { var cardProcess = await _dbContext.CardProcesses.FirstOrDefaultAsync(x => po.Id == x.PurchaseOrderId); if (cardProcess != null) // 增加空判断,避免空引用 { cardProcess.SettleStatus = ViewModels.SettleStatus.NA.ToString(); } var shipId = po.ShipId; var taskFile = await _dbContext.TaskFiles.FirstOrDefaultAsync(x => x.ShipNumber == shipId); if (taskFile == null) { continue; // 或根据业务逻辑处理taskFile不存在的情况 } var taskFilesExt = await _dbContext.TaskFileExts.FirstOrDefaultAsync(x => x.TaskFileId == taskFile.Id); if (taskFilesExt != null) { taskFilesExt.SettlStatus = ViewModels.SettleStatus.NA.ToString(); // 建议直接用枚举值而非ToString taskFilesExt.SettleStatus_NA += 1; // 修正笔误:jtaskFilesExt改为taskFilesExt taskFilesExt.SettleStatus_NA -= model.OldStatus == ViewModels.SettleStatus.NA ? 1 : 0; taskFilesExt.SettleStatus_Audited -= model.OldStatus == ViewModels.SettleStatus.Audited ? 1 : 0; taskFilesExt.SettlStatus_ReadyToPay -= model.OldStatus == ViewModels.SettleStatus.ReadyToPay ? 1 : 0; } } // 保存所有修改到数据库 await _dbContext.SaveChangesAsync();
性能优化建议(可选)
如果pOrders数量较多,上述代码会多次访问数据库,性能较差。可改为批量查询,减少数据库往返次数:
var pOrders = await _dbContext.POrders.Where(x => x.ShipId == data.shipNumber).ToListAsync(); var poIds = pOrders.Select(x => x.Id).ToList(); var shipIds = pOrders.Select(x => x.ShipId).Distinct().ToList(); // 批量查询所有需要的CardProcess var cardProcesses = await _dbContext.CardProcesses.Where(x => poIds.Contains(x.PurchaseOrderId)).ToListAsync(); // 批量查询所有需要的TaskFile var taskFiles = await _dbContext.TaskFiles.Where(x => shipIds.Contains(x.ShipNumber)).ToListAsync(); var taskFileIds = taskFiles.Select(x => x.Id).ToList(); // 批量查询所有需要的TaskFileExt var taskFileExts = await _dbContext.TaskFileExts.Where(x => taskFileIds.Contains(x.TaskFileId)).ToListAsync(); foreach (var po in pOrders) { var cardProcess = cardProcesses.FirstOrDefault(x => x.PurchaseOrderId == po.Id); if (cardProcess != null) { cardProcess.SettleStatus = ViewModels.SettleStatus.NA.ToString(); } var taskFile = taskFiles.FirstOrDefault(x => x.ShipNumber == po.ShipId); if (taskFile == null) { continue; } var taskFilesExt = taskFileExts.FirstOrDefault(x => x.TaskFileId == taskFile.Id); if (taskFilesExt != null) { taskFilesExt.SettlStatus = ViewModels.SettleStatus.NA.ToString(); taskFilesExt.SettleStatus_NA += 1; taskFilesExt.SettleStatus_NA -= model.OldStatus == ViewModels.SettleStatus.NA ? 1 : 0; taskFilesExt.SettleStatus_Audited -= model.OldStatus == ViewModels.SettleStatus.Audited ? 1 : 0; taskFilesExt.SettlStatus_ReadyToPay -= model.OldStatus == ViewModels.SettleStatus.ReadyToPay ? 1 : 0; } } await _dbContext.SaveChangesAsync();
内容的提问来源于stack exchange,提问作者sapter
相关产品推荐
相关产品推荐

