使用ReflectionIT.Mvc.Paging的CreateAsync时触发IAsyncQueryProvider异常
解决ReflectionIT.Mvc.Paging调用CreateAsync时的"IAsyncQueryProvider未实现"异常
问题根源
你遇到的异常本质是:传入PagingList.CreateAsync的IQueryable对象是内存集合转换而来的,它的查询提供器不支持Entity Framework的异步操作。具体原因如下:
- 你的
Repository.ReadAllAsync()方法调用了ToListAsync(),会立刻把所有数据从数据库加载到内存,返回的是IEnumerable<Entity> - 后续的
Select和AsQueryable()仅对内存中的集合做Linq操作,生成的IQueryable是基于内存的,没有EF Core的异步查询提供器,而PagingList.CreateAsync内部会尝试使用EF异步操作,因此抛出异常。
解决方案
核心思路是让分页逻辑在数据库端执行,而非先加载全量数据到内存再分页。需要修改仓库层和控制器代码:
1. 修改仓库接口与实现,返回IQueryable<TEntity>
IQueryable可以保留查询表达式、延迟执行,直到真正需要数据时才会去数据库查询,这样分页逻辑能下推到数据库,既高效又支持EF异步操作。
仓库接口修改:
public interface IRepository<TEntity> { IQueryable<TEntity> ReadAll(); // 移除async,直接返回IQueryable }
仓库实现修改:
public class Repository<TEntity> : IRepository<TEntity> where TEntity : class { private readonly DbSet<TEntity> dbSet; public Repository(DataContext context) => dbSet = context.Set<TEntity>(); public IQueryable<TEntity> ReadAll() => dbSet; // 直接返回DbSet(本身就是IQueryable) }
2. 调整控制器中的查询逻辑
直接操作IQueryable完成ViewModel映射,再传给PagingList.CreateAsync,让分页逻辑在数据库端执行:
public async Task<IActionResult> Index() { // 获取未执行的IQueryable查询,不提前加载数据 var query = _unitOfWork.RepositoryBase<Entity>().ReadAll() .Select(i => new ViewModel() { Id = i.Id, Name = i.Name, LastName = i.LastName }); // 传入支持EF异步的IQueryable,CreateAsync会自动处理分页查询 var pagingModel = await PagingList.CreateAsync(query, 10, 10, "Name", "Name"); pagingModel.RouteValue = new RouteValueDictionary { {"row", 10 } }; return View(pagingModel); }
3. (可选但推荐)优化DbContext注入方式
当前UnitOfWork自行实例化DataContext不符合依赖注入最佳实践,建议改为构造函数注入,并注册DataContext为Scoped生命周期:
在Program.cs中注册DbContext:
builder.Services.AddDbContext<DataContext>(options => options.UseSqlServer("Connection-String"));
修改UnitOfWork:
public class UnitOfWork : IUnitOfWork { private readonly DataContext context; // 通过构造函数注入DataContext public UnitOfWork(DataContext context) => this.context = context; public IRepository<TEntity> RepositoryBase<TEntity>() where TEntity : class { return new Repository<TEntity>(context); } }
修改完成后,PagingList.CreateAsync拿到的是EF Core原生的IQueryable,其查询提供器实现了IAsyncQueryProvider,即可正常执行异步分页操作,同时分页逻辑在数据库端执行,性能更优。
内容的提问来源于stack exchange,提问作者mamad2559
相关产品推荐
相关产品推荐

