ASP.NET Core MVC异步分页调用报错原因排查
问题原因及解决方案
这个错误的根源很明确——你提前把EF查询的结果加载到内存中了,然后把内存中的List转成了IQueryable,而这个内存版的IQueryable并没有实现EF异步操作需要的IAsyncQueryProvider。
具体来说:
- 你的代码里,先通过
foreach循环把EF查询的resultsObj(这本来是一个还没执行的EF延迟查询,也就是IQueryable)全部加载到内存的resultList里了。 - 然后你调用
resultList.AsQueryable(),这个时候得到的是Linq to Objects的IQueryable,它的底层查询提供者不是EF的异步查询提供者,所以当PaginatedList.CreateAsync里调用CountAsync、ToListAsync这些异步方法时,就会抛出那个错误。 - 微软官方指南里的
CreateAsync是直接对EF原生的IQueryable操作的,这样EF才能把分页逻辑翻译成SQL在数据库端执行,同时支持异步操作。
修改后的控制器代码
你不需要把查询结果先拉到内存里再转成List,直接在EF的IQueryable上完成投影和分页操作就好:
[HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> GetResultList(ResortDataJoinObj resDeals, int page = 1) { if (ModelState.IsValid) { // 直接投影成目标类型,不需要提前加载到内存 var resultsQuery = from rd in _db.ResortData join ra in _db.ResortAvailability on rd.RecNo equals ra.RecNoDate where ra.TotalPrice < Int32.Parse(resDeals.priceHighEnd) && ra.TotalPrice > Int32.Parse(resDeals.priceLowEnd) select new ResortDealResultsObject { Name = rd.Name, ImageUrl = rd.ImageUrl, ResortDetails = rd.ResortDetails, CheckIn = ra.CheckIn, Address = rd.Address, TotalPrice = ra.TotalPrice }; int pageSize = 3; // 直接传入EF的IQueryable,而不是内存List转的IQueryable var model = await PaginatedList<ResortDealResultsObject>.CreateAsync(resultsQuery, page, pageSize); ResortDataJoinObj joinObj = new ResortDataJoinObj(); joinObj.PageList = model; ViewBag.rowsReturned = true; return View(joinObj); } return View(resDeals); }
关键修改点
- 去掉内存加载步骤:直接将EF查询投影为
ResortDealResultsObject类型,避免用foreach把所有数据拉到内存。 - 传递原生EF查询:把
resultsQuery(EF原生的IQueryable)直接传给PaginatedList.CreateAsync,这样EF会处理异步操作,同时把分页逻辑翻译成SQL在数据库端执行,性能比加载全部数据到内存再分页要好得多。
内容的提问来源于stack exchange,提问作者loremIpsum1771
相关产品推荐
相关产品推荐

