.Net Core web API 分页列表 - 源 'IQueryable' 的提供程序未实现 'IAsyncQueryProvider'
.Net Core web API Paged List - The provider for the source 'IQueryable' doesn't implement 'IAsyncQueryProvider'
在 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);
}
和分页列表class:
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: The provider for the source
'IQueryable' doesn't implement 'IAsyncQueryProvider'. Only providers
that implement 'IAsyncQueryProvider' can be used for Entity Framework
asynchronous operations.
Whosebug 中的一些答案提供了一种使用仅用于 MVC 的 View() 的解决方法。
所有 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 查询转换仍然是试错游戏)。
在 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);
}
和分页列表class:
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: The provider for the source 'IQueryable' doesn't implement 'IAsyncQueryProvider'. Only providers that implement 'IAsyncQueryProvider' can be used for Entity Framework asynchronous operations.
Whosebug 中的一些答案提供了一种使用仅用于 MVC 的 View() 的解决方法。
所有 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 查询转换仍然是试错游戏)。