You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 11:53:13