禁用可空引用类型时HotChocolate GraphQL无默认构造函数报错问题
HotChocolate查询无默认构造函数实体的解决方案
问题背景
项目禁用隐式可空引用类型,实体类通过有参构造函数初始化所有非可空属性,使用HotChocolate查询时抛出错误:
"Type 'Dev.Taskify.Resources.Entities.TaskEntity' does not have a default constructor (Parameter 'type')"
添加默认构造函数后,IDE会警告非可空属性未初始化,希望在不添加默认构造函数的前提下让查询正常运行。
相关代码
实体类TaskEntity
public class TaskEntity { public TaskEntity(string name) { Name = name ?? throw new ArgumentNullException(nameof(name)); TaskCategoryEntities = new List<TaskCategoryEntity>(); } public Guid Id { get; set; } public string Name { get; set; } public ICollection<TaskCategoryEntity> TaskCategoryEntities { get; set; } }
查询类TaskQuery
[ExtendObjectType(nameof(Query))] public class TaskQuery { [UseProjection] [UseFiltering] [UseSorting] public IQueryable<TaskEntity> Tasks([Service] TaskifyDbContext context, [Service] IMapper mapper) { return context.Tasks; } }
解决方案
可以不添加默认构造函数,通过以下两种方式让查询正常工作:
1. 标记实体类的目标构造函数
在实体类的有参构造函数上添加[GraphQLConstructor]特性,明确告诉HotChocolate使用该构造函数实例化对象:
public class TaskEntity { [GraphQLConstructor] public TaskEntity(string name) { Name = name ?? throw new ArgumentNullException(nameof(name)); TaskCategoryEntities = new List<TaskCategoryEntity>(); } public Guid Id { get; set; } public string Name { get; set; } public ICollection<TaskCategoryEntity> TaskCategoryEntities { get; set; } }
这样既满足非可空属性的初始化要求,也不会触发IDE警告,同时HotChocolate会优先使用该构造函数创建实例。
2. 全局配置构造函数绑定策略
如果多个实体类都有类似需求,可以在GraphQL服务配置中全局设置构造函数解析规则,优先使用非默认构造函数:
builder.Services.AddGraphQLServer() .AddQueryType<TaskQuery>() .AddType<TaskEntity>() .SetConstructorBinding(ConstructorBindingBehavior.PreferNonDefault);
该配置会让HotChocolate自动选择实体类中参数最多的非默认构造函数,无需逐个添加特性。
原错误原因
HotChocolate默认的对象实例化逻辑依赖无参默认构造函数,当实体类没有提供默认构造函数时,它无法找到合适的方式创建实例,因此抛出"没有默认构造函数"的错误。如果不做上述配置,确实无法正常运行,因为框架无法自动识别并使用你的有参构造函数。
内容的提问来源于stack exchange,提问作者Giani Noyez
相关产品推荐
相关产品推荐

