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



在这里没有得到我的其他问题的答案之后,我做了一个不同的实现,这次是两个列表的联合而不是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);
}

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

系统。InvalidOperationException:源的提供者'IQueryable'不实现'IAsyncQueryProvider'。只有供应商实现'IAsyncQueryProvider'可以用于实体框架异步操作。

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

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

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

我所理解的问题是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查询翻译仍然是一个试错游戏)。

相关内容

  • 没有找到相关文章

最新更新