.Net Core Web API 分页列表 - 源“IQueryable”的提供程序未实现“IAsyncQueryProvider”

Posted

技术标签:

【中文标题】.Net Core Web API 分页列表 - 源“IQueryable”的提供程序未实现“IAsyncQueryProvider”【英文标题】:.Net Core web API Paged List - The provider for the source 'IQueryable' doesn't implement 'IAsyncQueryProvider' 【发布时间】:2021-12-09 17:26:56 【问题描述】:

在没有得到my other question here 的答案后,我做了一个不同的实现,这次是两个列表的联合,而不是 Automapper 映射投影。

public async Task<ActionResult<IEnumerable<MemberDto>>> GetMembersList([FromQuery] UserParams userParams)

    var members = await _unitOfWork.UserRepository.GetMembersAsync(userParams);

    Response.AddPaginationHeader(members.CurrentPage, members.PageSize,
        members.TotalCount, members.TotalPages);

    return Ok(members);

存储库:

    public async Task<PagedList<MemberDto>> GetMembersAsync(UserParams userParams)
    
        var members1 = await _context.Users
        .Where(x => x.Photos.Any(y => y.Url.Substring(0, 4) == "http"))
            .Select(m => new MemberDto
            
                Id = m.Id,
                UserName = m.UserName,
            ).ToListAsync();
    
        var member2 = await _context.Users
        .Where(x => x.Photos.Any(y => y.Url.Substring(0, 4) != "http"))
            .Select(m => new MemberDto
            
                Id = m.Id,
                UserName = m.UserName,
            ).ToListAsync();
    
        var members = members1.Union(member2).OrderBy(x => x.DisplayName).ToList();
        var query = members.AsQueryable();
query = query.Where(u => u.UserName == "John");
        return await PagedList<MemberDto>.CreateAsync(query, userParams.PageNumber, userParams.PageSize);
    

还有分页列表类:

public static async Task<PagedList<T>> CreateAsync(IQueryable<T> source, int pageNumber, 
    int pageSize)

    var count = await source.CountAsync();
    var items = await source.Skip((pageNumber - 1) * pageSize).Take(pageSize).ToListAsync();
    return new PagedList<T>(items, count, pageNumber, pageSize);

但是当我发送请求时,我收到以下错误:

System.InvalidOperationException:源的提供程序 “IQueryable”没有实现“IAsyncQueryProvider”。仅提供者 实现“IAsyncQueryProvider”的可用于实体框架 异步操作。

*** 中的一些答案提供了一种使用 View() 的解决方法,该方法仅用于 MVC。

【问题讨论】:

ToList().AsQueryable() - 这不再是 EF Core 可查询的,因此出现错误消息。尝试从代码中删除所有 ToList / ToListAsync 调用。 @IvanStoev 如果我这样做,查询将不会被翻译。 如果不能翻译,就不能高效分页(所有数据都已经加载到内存中了)。要在内存中进行分页,请创建并使用另一个非异步 Create 方法,该方法采用 IEnumerable&lt;T&gt; 并在内部使用同步 LINQ to Objects 方法(例如 source.Count())。 我已经创建了非异步方法,但仍然无法翻译。 【参考方案1】:

所有 EF Core 异步可查询扩展仅适用于 EF Core IQueryable 实现。 ToList() 将所有数据加载到内存中,而 AsQueryable() 是 LINQ to Objects IQueryable 实现,不能与 EF Core 扩展方法一起使用。

因此解决方案是删除所有ToList / await ToListAsync() 调用,从而保留结果EF Core IQueryable

据我了解,问题是 EF Core 无法翻译查询,因此您正在执行它并将结果放入内存中。所以这是一种解决方法,但是查询不能在服务器端有效地分页,因此不需要异步处理。你应该做的是像这样创建和使用同步Create方法重载

public static PagedList<T> Create(IEnumerable<T> source, int pageNumber, 
    int pageSize)

    var count = source.Count();
    var items = source.Skip((pageNumber - 1) * pageSize).Take(pageSize);
    return new PagedList<T>(items, count, pageNumber, pageSize);

并修改代码以使用它而不是CreateAsync

// original code...
var members = members1.Union(member2).OrderBy(x => x.DisplayName).ToList();
var query = members //.AsQueryable() not needed anymore
    .Where(u => u.UserName == "John");
return PagedList<MemberDto>.Create(query, userParams.PageNumber, userParams.PageSize);

但这只能作为最后的手段。在此之前,最好尝试使 EF Core 查询可翻译。在这种特殊情况下,我猜问题出在 Union 运算符(或其部分内部的东西)上,使用样本很容易消除(Union 看起来没有必要),但我想这不是真实情况。如果您提供更真实的示例以及目标 EF Core 版本,我们可以看看是否可以做一些事情(不幸的是,EF Core 查询翻译仍然是试错游戏)。

【讨论】:

我完全按照您的建议进行了尝试,但查询仍然无法翻译,错误消息:“无法翻译。要么以可翻译的形式重写查询,要么显式切换到客户端评估通过插入对“AsEnumerable”、“AsAsyncEnumerable”、“ToList”或“ToListAsync”的调用。” 哪个查询不能翻译?答案基于您在members1members2 是列表的问题中的原始代码,即已经执行和具体化的查询。因此没有查询。 需要对 members1 和 members2 进行 keepToList / await ToListAsync() 调用,然后使用非异步方法使其工作。 当然。我认为这很明显 - 要么保持所有部分可查询并使用 CreateAsync,要么使用列表(保持原始方法)并在最后使用 Create 仅使用列表进行零件工作,然后在我的原始代码中我有“var query = members.AsQueryable();”将其用于例如“query = query.Where(u => u.UserName == "John");"如果我使用“return PagedList.Create(query, userParams.PageNumber, userParams.PageSize);”它返回一个空结果。

以上是关于.Net Core Web API 分页列表 - 源“IQueryable”的提供程序未实现“IAsyncQueryProvider”的主要内容,如果未能解决你的问题,请参考以下文章

如何在 ASP.NET Core Web API 中发布对象列表

如何在 ASP Net Core Web API 上正确地将列表转换为 IQueryable

在 ASP.NET Core Web API 的已注册 .NET 数据提供程序列表中找不到指定的不变名称“System.Data.sqlClient”

.NET Core API 项目中的分页

在 ASP.NET Core Web API 中上传文件和 JSON

.NET Core Web API 中的图像上传