如何在HotChocolate中让仓储实现分页、筛选、排序与投影?
实现方案
要在HotChocolate中通过仓储模式处理分页、筛选、排序和投影,而非直接返回IQueryable,可以按以下步骤实现:
1. 从GraphQL解析器中获取查询参数
HotChocolate提供了直接注入查询参数或通过上下文提取的方式,拿到分页、筛选、排序、投影的相关信息。
方式一:直接注入参数
修改Query方法,直接注入所需的参数类型:
public class Query { [UsePaging] [UseFiltering] [UseSorting] [UseProjection] public IEnumerable<User> GetUsers( [Service] IUserRepository repository, PagingArguments pagingArgs, [Filter] Expression<Func<User, bool>> filter, [Sort] Expression<Func<IQueryable<User>, IOrderedQueryable<User>>> sort, [Projection] IProjectionContext projectionContext) { return repository.GetUsers(pagingArgs, filter, sort, projectionContext); } }
方式二:通过IResolverContext提取参数
如果需要更灵活的参数获取,可以注入IResolverContext并从中提取所有查询信息:
public class Query { [UsePaging] [UseFiltering] [UseSorting] [UseProjection] public IEnumerable<User> GetUsers( [Service] IUserRepository repository, IResolverContext context) { var pagingArgs = context.GetPagingArguments(); var filter = context.GetFilteringExpression<User>(); var sort = context.GetSortingExpression<User>(); var projectionContext = context.GetProjectionContext(); return repository.GetUsers(pagingArgs, filter, sort, projectionContext); } }
2. 定义仓储接口
根据需要接收的参数,定义仓储接口:
public interface IUserRepository { IEnumerable<User> GetUsers( PagingArguments pagingArgs, Expression<Func<User, bool>> filter, Expression<Func<IQueryable<User>, IOrderedQueryable<User>>> sort, IProjectionContext projectionContext); }
3. 实现仓储逻辑
在仓储实现中,基于数据源(如EF Core的DbSet)依次应用筛选、排序、投影和分页,最终返回结果:
public class UserRepository : IUserRepository { private readonly AppDbContext _dbContext; public UserRepository(AppDbContext dbContext) { _dbContext = dbContext; } public IEnumerable<User> GetUsers( PagingArguments pagingArgs, Expression<Func<User, bool>> filter, Expression<Func<IQueryable<User>, IOrderedQueryable<User>>> sort, IProjectionContext projectionContext) { IQueryable<User> query = _dbContext.Users; // 应用筛选条件(如果存在) if (filter != null) { query = query.Where(filter); } // 应用排序规则(如果存在) if (sort != null) { query = sort.Compile()(query); } // 应用投影(由HotChocolate的ProjectionContext处理复杂字段选择) query = projectionContext.ApplyProjection(query); // 应用分页 query = query.Skip(pagingArgs.Skip).Take(pagingArgs.Take); // 执行查询并返回结果 return query.ToList(); } }
4. 注册HotChocolate服务
确保在项目启动时注册必要的GraphQL服务:
builder.Services.AddGraphQLServer() .AddQueryType<Query>() .AddProjections() .AddFiltering() .AddSorting() .AddPaging(); // 注册仓储 builder.Services.AddScoped<IUserRepository, UserRepository>();
关键注意事项
- 所有表达式(筛选、排序)都会被EF Core转换为SQL执行,避免内存中处理大量数据的性能问题。
IProjectionContext可以处理复杂的嵌套字段投影,无需手动编写Select表达式。- 如果没有传入筛选、排序参数,对应的值会为
null,需在仓储中做空值判断以避免异常。
内容的提问来源于stack exchange,提问作者me.at.coding
相关产品推荐
相关产品推荐

