数据库关联表场景下for与foreach循环的差异及报错排查
问题原因及解决方法
为什么foreach循环会报错
你直接遍历的objList是EF Core返回的延迟查询结果(IEnumerable<Product>),这种情况下每次foreach迭代都会触发一次数据库查询获取单个Product实体,再加上循环内每次都去查询Category,短时间内大量的数据库小请求会耗尽连接池资源,导致“服务器已被占用”的错误。
而for循环先通过ToArray()把所有Product一次性加载到内存,遍历的是本地集合,不会重复触发Product的数据库查询,对数据库连接的占用更可控,所以能正常运行。
解决方法
方法1:先将Product加载到内存再用foreach遍历
和for循环的思路一致,先把数据拉到本地内存,再遍历操作:
public IActionResult Index() { var objList = _db.Product.ToList(); // 提前加载所有Product到内存 foreach (var item in objList) { item.Category = _db.Category.FirstOrDefault(category => category.Id == item.CategoryId); } return View(objList); }
方法2:使用EF Core的预加载(Include)优化查询(推荐)
上面的方法还是会有N+1查询问题(1次查Product,N次查Category),更高效的方式是用Include方法一次性关联查询Product和对应的Category,避免循环查询数据库:
using Microsoft.EntityFrameworkCore; // 需要引入该命名空间 public IActionResult Index() { // 通过Include一次性查询所有Product及其关联的Category var objList = _db.Product.Include(p => p.Category).ToList(); return View(objList); }
这种方式会生成JOIN语句,一次数据库请求就能获取所有需要的数据,性能更好,也从根源上避免了连接占用的问题。
内容的提问来源于stack exchange,提问作者Jeffrey Willis
相关产品推荐
相关产品推荐

