Entity Framework Automapper 分页 IQueryable' 没有实现 'IAsyncQueryProvider
Entity Framework Automapper pagination IQueryable' doesn't implement 'IAsyncQueryProvider
我有两个实体,AppUser
和 InterestTag
:
public class AppUser : IdentityUser<int>
{
public ICollection<InterestTag> InterestTags { get; set; }
}
public class InterestTag
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<AppUser> AppUsers { get; set; }
}
它们在 DataContext
中配置为具有直接的多对多关系
builder.Entity<AppUser>()
.HasMany(u => u.InterestTags)
.WithMany(ut => ut.AppUsers);
我正在尝试制作一种方法,通过用户的用户名获取用户的所有 InterestTags
,然后将 InterestTag
投影到 InterestTagDto
并对结果进行分页。
InterestTagDto
:
public class InterestTagDto
{
public int Id { get; set; }
public string Name { get; set; }
}
映射配置为
CreateMap<InterestTag, InterestTagDto>();
PagedList
class:
public class PagedList<T> : List<T>
{
public PagedList(IEnumerable<T> items, int count, int pageNumber, int pageSize)
{
CurrentPage = pageNumber;
TotalPages = (int)Math.Ceiling(count / (double)pageSize);
PageSize = pageSize;
TotalCount = count;
AddRange(items);
}
public int CurrentPage { get; set; }
public int TotalPages { get; set; }
public int PageSize { get; set; }
public int TotalCount { get; set; }
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);
}
}
我目前的方法:
public async Task<PagedList<InterestTagDto>> GetUserInterestTagsAsync(string username)
{
var query = (await _context.Users.Include(u => u.InterestTags).SingleOrDefaultAsync(u => u.UserName == username)).InterestTags.AsQueryable();
return await PagedList<InterestTagDto>.CreateAsync(query.ProjectTo<InterestTagDto>(_mapper.ConfigurationProvider)
.AsNoTracking(), 1, 20);
}
在线
var count = await source.CountAsync();
of PagedList<>
, 我得到一个错误
The provider for the source 'IQueryable' doesn't implement 'IAsyncQueryProvider'. Only providers that implement 'IAsyncQueryProvider' can be used for Entity Framework asynchronous operations
我认为问题是在它映射到 DTO 之后它的类型是一个 HashSet:
{System.Collections.Generic.HashSet`1[API.Entities.InterestTag].Select(dtoInterestTag => new InterestTagDto() {Id = dtoInterestTag.Id, Name = dtoInterestTag.Name})}
我有一个类似的函数可以工作,它获取 AppUsers
的列表并将其映射到 MemberDto
并使用相同的 PagedList
class.
映射后类型为:
{Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable<API.DTOs.MemberDto>}
非常感谢任何帮助。谢谢!
问题出在你的“查询”(实际上不是查询,而是具体化的查询结果):
var query = (await _context.Users.Include(u => u.InterestTags).SingleOrDefaultAsync(u => u.UserName == username)).InterestTags.AsQueryable();
您正在使用 SingleOrDefaultAsync
实现您的查询,因此 EF 将调用数据库并使用 .NET 类 和集合将数据映射到内存,使 AppUser.InterestTags
成为一些集合并构建集合通常不实施 IAsyncQueryProvider
,这会导致您遇到错误。
有几种可能的解决方法:
创建 PagedList.CreateAsync
重载,它接受 IEnumerable
并将您的查询结果作为普通可枚举的、不可查询的传递给它。
重写查询,使其实际上是一个查询。像这样:
var query = await _context.Users
.Where(u => u.UserName == username)) // assuming UserName is unique
.SelectMany(t => t.InterestTags);
// pass to CreateAsync ...
P.S.
通常也尽量防止过度获取(您只需要 InterestTags
但从数据库中获取来自 User
table 的其余用户数据,尽管它不会导致提供的错误)。
我有两个实体,AppUser
和 InterestTag
:
public class AppUser : IdentityUser<int>
{
public ICollection<InterestTag> InterestTags { get; set; }
}
public class InterestTag
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<AppUser> AppUsers { get; set; }
}
它们在 DataContext
中配置为具有直接的多对多关系
builder.Entity<AppUser>()
.HasMany(u => u.InterestTags)
.WithMany(ut => ut.AppUsers);
我正在尝试制作一种方法,通过用户的用户名获取用户的所有 InterestTags
,然后将 InterestTag
投影到 InterestTagDto
并对结果进行分页。
InterestTagDto
:
public class InterestTagDto
{
public int Id { get; set; }
public string Name { get; set; }
}
映射配置为
CreateMap<InterestTag, InterestTagDto>();
PagedList
class:
public class PagedList<T> : List<T>
{
public PagedList(IEnumerable<T> items, int count, int pageNumber, int pageSize)
{
CurrentPage = pageNumber;
TotalPages = (int)Math.Ceiling(count / (double)pageSize);
PageSize = pageSize;
TotalCount = count;
AddRange(items);
}
public int CurrentPage { get; set; }
public int TotalPages { get; set; }
public int PageSize { get; set; }
public int TotalCount { get; set; }
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);
}
}
我目前的方法:
public async Task<PagedList<InterestTagDto>> GetUserInterestTagsAsync(string username)
{
var query = (await _context.Users.Include(u => u.InterestTags).SingleOrDefaultAsync(u => u.UserName == username)).InterestTags.AsQueryable();
return await PagedList<InterestTagDto>.CreateAsync(query.ProjectTo<InterestTagDto>(_mapper.ConfigurationProvider)
.AsNoTracking(), 1, 20);
}
在线
var count = await source.CountAsync();
of PagedList<>
, 我得到一个错误
The provider for the source 'IQueryable' doesn't implement 'IAsyncQueryProvider'. Only providers that implement 'IAsyncQueryProvider' can be used for Entity Framework asynchronous operations
我认为问题是在它映射到 DTO 之后它的类型是一个 HashSet:
{System.Collections.Generic.HashSet`1[API.Entities.InterestTag].Select(dtoInterestTag => new InterestTagDto() {Id = dtoInterestTag.Id, Name = dtoInterestTag.Name})}
我有一个类似的函数可以工作,它获取 AppUsers
的列表并将其映射到 MemberDto
并使用相同的 PagedList
class.
映射后类型为:
{Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable<API.DTOs.MemberDto>}
非常感谢任何帮助。谢谢!
问题出在你的“查询”(实际上不是查询,而是具体化的查询结果):
var query = (await _context.Users.Include(u => u.InterestTags).SingleOrDefaultAsync(u => u.UserName == username)).InterestTags.AsQueryable();
您正在使用 SingleOrDefaultAsync
实现您的查询,因此 EF 将调用数据库并使用 .NET 类 和集合将数据映射到内存,使 AppUser.InterestTags
成为一些集合并构建集合通常不实施 IAsyncQueryProvider
,这会导致您遇到错误。
有几种可能的解决方法:
创建
PagedList.CreateAsync
重载,它接受IEnumerable
并将您的查询结果作为普通可枚举的、不可查询的传递给它。重写查询,使其实际上是一个查询。像这样:
var query = await _context.Users
.Where(u => u.UserName == username)) // assuming UserName is unique
.SelectMany(t => t.InterestTags);
// pass to CreateAsync ...
P.S.
通常也尽量防止过度获取(您只需要 InterestTags
但从数据库中获取来自 User
table 的其余用户数据,尽管它不会导致提供的错误)。