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

ASP.NET Core 7中HotChocolate添加GraphQL对象类型报错求助

在ASP.NET Core 7中使用HotChocolate开发GraphQL API的问题排查与解决

问题场景

在ASP.NET Core 7项目中使用HotChocolate库开发GraphQL API时,添加PlatformType类后,API请求无法正常处理。

相关代码

Query类

using CommanderGQL.Data;
using CommanderGQL.Models;

namespace CommanderGQL.GraphQL
{
    public class Query
    {
        [UseDbContext(typeof(AppDbContext))]
        [UseProjection]
        public IQueryable<Platform> GetPlatform([ScopedService] AppDbContext context)
        {
            return context.Platforms;
        }

        [UseDbContext(typeof(AppDbContext))]
        [UseProjection]
        public IQueryable<Command> GetCommand([ScopedService] AppDbContext context)
        {
            return context.Commands;
        }
    }
}

Platform实体类

using System.ComponentModel.DataAnnotations;

namespace CommanderGQL.Models
{
    public class Platform
    {
        [Key]
        public int Id { get; set; }
        [Required]
        public string Name { get; set; } = string.Empty;
        public string LicenseKey { get; set; } = string.Empty;
        public ICollection<Command> Commands { get; set; } = new List<Command>();
    }
}

Command实体类

using System.ComponentModel.DataAnnotations;

namespace CommanderGQL.Models
{
    public class Command
    {
        [Key]
        public int Id { get; set; }
        [Required]
        public string HowTo { get; set; }
        [Required]
        public string CommandLine { get; set; }
        [Required]
        public int PlatformId { get; set; }
        public Platform Platform { get; set; }
    }
}

PlatformType类(疑似问题代码)

using CommanderGQL.Data;
using CommanderGQL.Models;

namespace CommanderGQL.GraphQL.Platforms
{
    public class PlatformType : ObjectType<Platform>
    {
        protected override void Configure(IObjectTypeDescriptor<Platform> descriptor)
        {
            descriptor.Description("Represents any software that has a command line interface");

            descriptor
                .Field(p => p.LicenseKey).Ignore();

            descriptor
                .Field(p => p.Commands)
                .ResolveWith<Resolvers>(p => p.GetCommands(default!, default!))
                .UseDbContext<AppDbContext>()
                .Description("This is the list of available commands for this platform");
        }

        private class Resolvers
        {
            public IQueryable<Command> GetCommands(Platform platform, [ScopedService] AppDbContext context) 
            {
                return context.Commands.Where(p => p.PlatformId == platform.Id);
            }
        }
    }
}

Program.cs配置

builder.Services
    .AddGraphQLServer()
    .AddQueryType<Query>()
    .AddType<PlatformType>()
    .AddType<CommandType>()
    .AddFiltering()
    .AddSorting()
    .AddProjections();

测试请求与错误响应

执行GraphQL请求:

query {
  platform {
    id
    name
    commands {
      howTo
      commandLine
      platformId
    }
  }
}

得到错误响应:

{
  "errors": [
    {
      "message": "There was no argument with the name `platform` found on the field `commands`.",
      "locations": [
        {
          "line": 6,
          "column": 5
        }
      ],
      "path": [
        "platform",
        2,
        "commands"
      ],
      "extensions": {
        "fieldName": "commands",
        "argumentName": "platform"
      }
    },
    {
      "message": "There was no argument with the name `platform` found on the field `commands`.",
      "locations": [
        {
          "line": 6,
          "column": 5
        }
      ],
      "path": [
        "platform",
        1,
        "commands"
      ],
      "extensions": {
        "fieldName": "commands",
        "argumentName": "platform"
      }
    },
    {
      "message": "There was no argument with the name `platform` found on the field `commands`.",
      "locations": [
        {
          "line": 6,
          "column": 5
        }
      ],
      "path": [
        "platform",
        0,
        "commands"
      ],
      "extensions": {
        "fieldName": "commands",
        "argumentName": "platform"
      }
    }
  ]
}

问题原因

错误核心是:在PlatformType中配置Commands字段时,使用ResolveWith指定解析方法时,HotChocolate错误地将方法的第一个参数Platform platform识别为GraphQL字段的输入参数。但实际上这个参数是当前字段的父对象实例(即当前查询到的Platform对象),不需要作为请求参数传入,因此查询时找不到对应的platform参数而报错。

解决方案

方案一:用[Parent]标记父对象参数

修改Resolvers类的GetCommands方法,给platform参数加上[Parent]特性,明确告知HotChocolate这是父对象,不是输入参数:

private class Resolvers
{
    public IQueryable<Command> GetCommands([Parent] Platform platform, [ScopedService] AppDbContext context) 
    {
        return context.Commands.Where(p => p.PlatformId == platform.Id);
    }
}

方案二:改用Resolve方法直接编写逻辑

替换ResolveWith为Resolve,直接在配置逻辑中获取父对象和服务,避免参数解析问题:

descriptor
    .Field(p => p.Commands)
    .Resolve(ctx => 
    {
        // 获取父对象(当前Platform实例)
        var platform = ctx.Parent<Platform>();
        // 获取DbContext服务
        var dbContext = ctx.Service<AppDbContext>();
        return dbContext.Commands.Where(p => p.PlatformId == platform.Id);
    })
    .UseDbContext<AppDbContext>()
    .Description("This is the list of available commands for this platform");

可选优化:利用EF Core导航属性自动加载

如果你的EF Core已经正确配置了Platform和Command的关联关系(如在DbContext中设置了导航属性),其实可以不需要手动编写Resolver。HotChocolate会自动通过EF Core的导航属性加载关联数据,只需确保Query类中使用了UseProjection特性,这样代码会更简洁。

正确添加GraphQL类型的要点

  1. 自定义ObjectType时,确保字段配置的参数类型被正确识别:父对象用[Parent]标记,服务用[ScopedService]等标记,避免被误识别为输入参数。
  2. 对于实体间的关联字段,优先利用EF Core导航属性,减少手动Resolver的编写。
  3. 在Program.cs中通过AddType<T>()注册自定义类型,确保GraphQL Server能识别这些类型。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 06:54:53