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

Hot Chocolate GraphQL:如何解析使用被忽略字段的投影字段

Hot Chocolate忽略字段的投影问题解决方案

问题背景

数据模型ItemData包含StartTime和EndTime字段,需要隐藏这两个字段,合并为一个duration字段对外暴露。配置ItemType时用Ignore方法隐藏了原字段,通过ResolveWith实现duration字段的解析,但开启UseProjection后,Resolver无法获取到StartTime和EndTime的值——因为这两个字段没有被包含在EF Core的投影查询中,且IsProjected(true)在被Ignore的字段上不生效。目前官方已在处理相关Issue#4192。

临时解决方案

在官方修复完成前,可采用以下几种方式解决:

1. 隐藏字段而非直接忽略

取消Ignore配置,改为通过权限或字段可见性限制外部访问,同时标记字段需要投影:

// 配置StartTime和EndTime为可投影但外部不可查询
descriptor.Field(x => x.StartTime)
    .IsProjected(true)
    .Type<StringType>()
    .Authorize("Internal"); // 通过权限规则禁止外部客户端查询
descriptor.Field(x => x.EndTime)
    .IsProjected(true)
    .Type<StringType>()
    .Authorize("Internal");

// 继续配置duration字段
descriptor.Field("duration")
    .ResolveWith<TheResolver>(resolver => resolver.GetDuration(default!))
    .Type<DurationType>();

这种方式既保证字段被包含在投影中,又不会对外暴露,Resolver能正常获取值。

2. 自定义投影拦截器

通过查询执行拦截器,在查询包含duration字段时,手动添加StartTime和EndTime到投影列表:

public class DurationProjectionInterceptor : QueryExecutionInterceptor
{
    public override ValueTask<ExecutionResult> OnExecuteAsync(
        QueryExecutor executor,
        IQueryRequest request,
        CancellationToken cancellationToken)
    {
        // 检查查询是否包含duration字段(可根据实际需求优化判断逻辑)
        if (request.Query.Contains("duration"))
        {
            var projection = request.Projection ?? new ProjectionNode();
            projection = projection.AddFields(nameof(ItemData.StartTime), nameof(ItemData.EndTime));
            request.SetProjection(projection);
        }
        return base.OnExecuteAsync(executor, request, cancellationToken);
    }
}

注册拦截器:

services.AddGraphQLServer()
    .AddQueryType<Query>()
    .AddType<ItemType>()
    .UseProjection()
    .AddQueryExecutionInterceptor<DurationProjectionInterceptor>();

3. Resolver中显式加载字段

在Resolver里通过EF Core的Entry API显式加载StartTime和EndTime:

public class TheResolver
{
    private readonly AppDbContext _dbContext;

    public TheResolver(AppDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public async Task<DurationType> GetDuration(ItemData item)
    {
        // 显式加载忽略的字段
        await _dbContext.Entry(item).Reference(x => x.StartTime).LoadAsync();
        await _dbContext.Entry(item).Reference(x => x.EndTime).LoadAsync();

        return new DurationType
        {
            Start = item.StartTime,
            End = item.EndTime
        };
    }
}

注意:此方法会额外触发数据库查询,可能影响性能,适合小数据量场景。

官方进展

官方已在处理Issue#4192,修复后预计可直接通过配置IsProjected(true)让被忽略的字段参与投影,建议关注官方更新。

内容的提问来源于stack exchange,提问作者anuith

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 20:39:07