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
相关产品推荐
相关产品推荐

