如何在HotChocolate FieldResolver中获取当前实体ID关联错误数据?
问题描述
我编写了以下代码,想要从一个缓存错误以提升性能的服务中获取完整错误列表,为已解析的实体项附加错误列表:
public class MyEntityExtensions : ObjectType<MyEntity> { protected override void Configure(IObjectTypeDescriptor<MyEntity> descriptor) { descriptor .Field("errors") .Type(typeof(List<Error>)) .Resolve(async context => { var errorCache = context.Service<ErrorCache>(); var entityId = ???; var errors = await errorCache.Get(entityId); return errors ; }); } }
疑问点
- 如何获取当前实体的
Id属性,作为参数传入缓存服务? - 尝试过声明式方法,但无法强制执行解析器顺序或字段依赖;运行时方法里
MiddlewareContext也没有持有同一对象其他字段的信息,唯一能引用已解析项的方式是.Parent<>(),但这不是层级结构。试过多种中间件设置和Use()调整执行顺序都没成功。 - 当前方法是否可行?如果不可行,有没有不用把错误作为完全独立数据源拼接的替代方案?
解决方案
1. 获取当前实体的Id属性
在解析器中,你可以直接通过context.Parent<MyEntity>()获取当前正在处理的MyEntity实例,进而访问它的Id属性,这是最直接的方式:
.Resolve(async context => { var errorCache = context.Service<ErrorCache>(); // 获取当前实体实例 var currentEntity = context.Parent<MyEntity>(); var entityId = currentEntity.Id; var errors = await errorCache.Get(entityId); return errors; });
这里的context.Parent<T>()专门用于获取当前字段所属的父对象(也就是当前的MyEntity实例),它不需要依赖其他字段的解析顺序——因为这个字段的解析是基于已经加载完成的MyEntity实例本身,而非等待其他字段解析结果。
2. 当前方法的可行性及替代方案
你的当前方法是完全可行的,context.Parent<T>()就是正确获取当前实体实例的标准方式,如果之前用的时候没成功,大概率是配置问题,比如MyEntity的类型映射是否正确,或者解析上下文的父对象类型是否匹配。
如果需要更灵活的实现,还有两种替代方案:
- 实体加载时预绑定错误:如果获取
MyEntity的查询逻辑可以同时拉取错误数据,直接把错误作为MyEntity的一个属性,这样就不需要单独的字段解析器。但这种方式要注意性能,只有当错误数据和实体数据能批量加载时才推荐。 - 批量加载错误提升性能:如果一次请求会处理多个
MyEntity实例,可以通过全局中间件收集所有需要查询的entityId,批量从缓存获取错误后再分配给对应实体,避免多次缓存查询:
之后在解析器中直接从批量数据中取对应实体的错误:// 批量加载错误的中间件示例 public class BatchErrorLoadingMiddleware : IMiddleware { public async ValueTask InvokeAsync(IResolverContext context, MiddlewareDelegate next) { await next(context); // 标记需要批量查询错误的实体ID if (context.Field.DeclaringType.Name == nameof(MyEntity) && context.Field.Name == "errors") { var entityIds = context.BatchData.GetOrAdd("entityIds", () => new List<Guid>()); var entity = context.Parent<MyEntity>(); entityIds.Add(entity.Id); } // 在请求收尾阶段批量获取错误 if (context.IsFinalResolver) { if (context.BatchData.TryGetValue("entityIds", out var idsObj) && idsObj is List<Guid> entityIds) { var errorCache = context.Service<ErrorCache>(); var allErrors = await errorCache.GetBatch(entityIds); context.BatchData["errorsMap"] = allErrors.ToDictionary(e => e.EntityId, e => e.Errors); } } } }.Resolve(async context => { var currentEntity = context.Parent<MyEntity>(); if (context.BatchData.TryGetValue("errorsMap", out var errorsObj) && errorsObj is Dictionary<Guid, List<Error>> errorsMap) { errorsMap.TryGetValue(currentEntity.Id, out var errors); return errors ?? new List<Error>(); } return new List<Error>(); });
内容的提问来源于stack exchange,提问作者JRoughan
相关产品推荐
相关产品推荐

