ASP.NET MVC C#中保存记录后批量更新同ProductID的Qty_Available字段
解决EF中"New transaction not allowed because there are other threads running in the session"错误
问题原因
你这段代码的核心问题有两个:
- 直接遍历EF的
IQueryable延迟加载结果(db.ProductOrders.Where(...)未立即执行查询),同时在循环内调用SaveChanges(),导致DbContext会话中同时存在查询线程和修改操作,触发事务冲突。 - 每次循环都调用
SaveChanges(),不仅效率极低,还会加剧线程冲突的概率。
修正方案
- 先将需要修改的记录一次性加载到内存(用
ToList()触发立即查询),避免延迟加载占用会话。 - 批量修改所有符合条件的记录字段。
- 只调用**一次
SaveChanges()**完成所有更新。
修正后的代码
// 获取新保存的订单记录 var productOrder = db.ProductOrders.Find(id); if (productOrder == null) { // 处理记录不存在的情况,比如抛出异常或返回错误提示 return; } // 将所有同ProductID的记录加载到内存,避免延迟加载的会话冲突 var sameProductOrders = db.ProductOrders.Where(x => x.ProductID == productOrder.ProductID).ToList(); // 批量更新Qty_Available字段 foreach (var item in sameProductOrders) { item.Qty_Available = productOrder.Qty_Available; db.Entry(item).State = EntityState.Modified; } // 一次性提交所有修改 db.SaveChanges();
进阶优化(EF Core 3.0+)
如果使用EF Core,推荐直接用ExecuteUpdate做数据库层面的批量更新,无需加载所有实体,性能更优:
var productOrder = db.ProductOrders.Find(id); if (productOrder == null) { return; } // 直接在数据库执行批量更新,跳过实体加载步骤 db.ProductOrders .Where(x => x.ProductID == productOrder.ProductID) .ExecuteUpdate(setters => setters.SetProperty(x => x.Qty_Available, productOrder.Qty_Available));
额外注意事项
- 确保
id对应的记录已成功保存到数据库(你提到是保存新记录后获取,此条件已满足)。 - 若业务存在高并发场景,建议添加事务处理避免数据不一致:
using (var transaction = db.Database.BeginTransaction()) { try { // 执行上述更新逻辑 db.SaveChanges(); transaction.Commit(); } catch (Exception) { transaction.Rollback(); throw; } }
内容的提问来源于stack exchange,提问作者Kip M.
相关产品推荐
相关产品推荐

