ASP.NET Core 6 Minimal API访问SQL Server时遇DataReader已打开错误
解决“已有打开的DataReader关联此连接,必须先关闭”错误
问题根源
你在查询Inquiry的投影逻辑(select new Inquiry)里直接调用了GetLocationById方法,而这个方法又用同一个CCTPDbContext发起了新的数据库查询。此时第一个db.Inquiry的查询还在执行(EF Core默认延迟执行,枚举结果时才会真正访问数据库),导致同一个数据库连接上同时有两个DataReader在运行——SQL Server默认不允许这种情况,因此抛出错误。
你之前尝试的Dispose和using语句无效,是因为你错误地复用了已有的DbContext实例,而非解决“同时执行多个查询”的核心问题。
解决方案
方案1:先加载基础数据到内存,再查询关联数据
先把Inquiry的基础数据完整查询出来并加载到内存,确保第一个数据库查询完成后,再调用GetLocationById获取关联的Location:
修改Program.cs中的端点代码:
app.MapGet("/Inquiry/test/{InquiyId}", async (CCTPDbContext db, HttpRequest request) => { int InquiryId = Int32.Parse(request.RouteValues["InquiyId"].ToString()); // 先查询并加载Inquiry数据到内存 var inquiryFromDb = await db.Inquiry.FirstOrDefaultAsync(i => i.Id == InquiryId); if (inquiryFromDb == null) { return Results.NotFound(); } // 此时第一个查询已完成,连接已释放,再调用GetLocationById var inquiryZ = new Inquiry { Id = inquiryFromDb.Id, LocationId = inquiryFromDb.LocationId, Description = inquiryFromDb.Description, DateFrom = inquiryFromDb.DateFrom, DateTo = inquiryFromDb.DateTo, LocationLautLocationId = new Location().GetLocationById(db, inquiryFromDb.LocationId), // 其他属性赋值... }; return Results.Ok(inquiryZ); });
方案2:使用EF Core导航属性(推荐)
如果Inquiry实体中已经定义了到Location的导航属性(这是EF Core的最佳实践),可以直接用Include进行关联查询,一次数据库请求就能获取所有需要的数据,从根源避免多DataReader问题:
- 确保
Inquiry实体包含导航属性:
public class Inquiry { // 现有属性... public int LocationId { get; set; } public Location? LocationLautLocationId { get; set; } // 导航属性 }
- 修改端点查询代码:
app.MapGet("/Inquiry/test/{InquiyId}", async (CCTPDbContext db, HttpRequest request) => { int InquiryId = Int32.Parse(request.RouteValues["InquiyId"].ToString()); var inquiryZ = await db.Inquiry .Include(i => i.LocationLautLocationId) // 关联查询Location表 .Where(i => i.Id == InquiryId) .Select(i => new Inquiry { Id = i.Id, LocationId = i.LocationId, Description = i.Description, DateFrom = i.DateFrom, DateTo = i.DateTo, LocationLautLocationId = i.LocationLautLocationId, // 其他属性... }) .FirstOrDefaultAsync(); if (inquiryZ == null) { return Results.NotFound(); } return Results.Ok(inquiryZ); });
这种方式不仅解决了错误,还减少了数据库请求次数,性能更优。
内容的提问来源于stack exchange,提问作者Spacewalker
相关产品推荐
相关产品推荐

