在 v11 中进行演练时生成的奇怪模式
Strange schema generated when doing walkthrough in v11
我正在尝试完成一个非常简单的 graphql 服务器示例并选择了它。
https://www.blexin.com/en-US/Article/Blog/Creating-our-API-with-GraphQL-and-Hot-Chocolate-79
(没有SQL后端,我想端到端地理解它,所以这有数据的内存表)。
我几乎按照演练实现了它(一些属性,例如“[UseFiltering]”无法编译,我只是暂时将它们注释掉)。
虽然我的启动看起来像这样
services.AddSingleton<IAuthorService, InMemoryAuthorService>();
services.AddSingleton<IBookService, InMemoryBookService>();
services.
AddGraphQLServer().
AddType<AuthorType>().
AddType<BookType>().
AddQueryType<GraphQL.Query>();
当我试图查询一本书的作者时,看起来很奇怪
{
books {
title
authorId
price
author {
name
surname
}
}
}
香蕉蛋糕流行抱怨
field author argument book of type BookInput! is required
(如果我不要求作者,那么一切正常)
booktype 看起来像这样(根据演练)
public class BookType : ObjectType<Book>
{
protected override void Configure(IObjectTypeDescriptor<Book> descriptor)
{
descriptor.Field(b => b.Id).Type<IdType>();
descriptor.Field(b => b.Title).Type<StringType>();
descriptor.Field(b => b.Price).Type<DecimalType>();
descriptor.Field<AuthorResolver>(t => t.GetAuthor(default, default));
}
}
作者解析器看起来像这样
public class AuthorResolver
{
private readonly IAuthorService _authorService;
public AuthorResolver([Service]IAuthorService authorService)
{
_authorService = authorService;
}
public Author GetAuthor(Book book, IResolverContext ctx)
{
return _authorService.GetAll().Where(a => a.Id == book.AuthorId).FirstOrDefault();
}
}
同样,按照演练。
我基本上理解错误,但我不明白这是怎么回事,不知何故,“书”父级必须进入 AuthorResolver 上的 GetAuthor 方法....我遗漏了一些魔法,或者 v11 缺少一些魔法。
P.S.
我更喜欢声明式类型化的表达式,而不是反身魔法...所以也许我遗漏了什么
问题是我的 AuthorResolver 上的 GetAuthor 方法缺少“Parent”属性,无法触发一些魔法....
public Author GetAuthor([Parent]Book book, IResolverContext ctx)
{
return _authorService.GetAll().Where(a => a.Id == book.AuthorId).FirstOrDefault();
}
理想情况下,我想删除这个自定义属性魔法。
实际上,当前版本 11.0.9 不需要 [Parent] 属性。我特别检查了解析器 class。但在下面的示例中,我删除了解析器,因为在您的情况下使用它太冗长了。另外,我删除了 Book 参数以显示从解析器上下文获取该参数的方法。
using System.Linq;
using HotChocolate.Resolvers;
using HotChocolate.Types;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace Ademchenko.GraphQLWorkshop
{
public class Author
{
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
}
public class Book
{
public int Id { get; set; }
public string Title { get; set; }
public int AuthorId { get; set; }
public decimal Price { get; set; }
}
public interface IAuthorService { IQueryable<Author> GetAll(); }
public interface IBookService { IQueryable<Book> GetAll(); }
public class InMemoryAuthorService : IAuthorService
{
private readonly Author[] _staticAuthors = {
new Author {Name = "FooAuthor", Surname = "FooSurname", Id = 1},
new Author {Name = "BarAuthor", Surname = "BarSurname", Id = 2},
};
public IQueryable<Author> GetAll() => _staticAuthors.AsQueryable();
}
public class InMemoryBookService : IBookService
{
private readonly Book[] _staticBooks = {
new Book {Id = 11, Title = "FooBook", AuthorId = 1, Price = 10.2m},
new Book {Id = 22, Title = "BarBook", AuthorId = 2, Price = 20.2m},
};
public IQueryable<Book> GetAll() => _staticBooks.AsQueryable();
}
public class Query
{
public IQueryable<Book> GetBooks(IResolverContext ctx) => ctx.Service<IBookService>().GetAll();
}
public class BookType : ObjectType<Book>
{
protected override void Configure(IObjectTypeDescriptor<Book> descriptor)
{
descriptor.Field(b => b.Id).Type<IdType>();
descriptor.Field("author").Resolve((ctx, ct) => ctx.Service<IAuthorService>().GetAll().FirstOrDefault(a => a.Id == ctx.Parent<Book>().AuthorId));
}
}
public class Startup
{
public IConfiguration Configuration { get; }
public Startup(IConfiguration configuration) => Configuration = configuration;
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSingleton<IAuthorService, InMemoryAuthorService>();
services.AddSingleton<IBookService, InMemoryBookService>();
services.AddGraphQLServer()
.AddQueryType<Query>()
.AddType<BookType>();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) => app.UseRouting().UseEndpoints(endpoints => endpoints.MapGraphQL());
}
}
这是一个完整的示例,所以如果您向端点发出以下请求:
{
books
{
id,
title
authorId
author
{
id
name
}
}
}
您将获得:
{
"data": {
"books": [
{
"id": "11",
"title": "FooBook",
"authorId": 1,
"author": {
"id": 1,
"name": "FooAuthor"
}
},
{
"id": "22",
"title": "BarBook",
"authorId": 2,
"author": {
"id": 2,
"name": "BarAuthor"
}
}
]
}
}
我正在尝试完成一个非常简单的 graphql 服务器示例并选择了它。
https://www.blexin.com/en-US/Article/Blog/Creating-our-API-with-GraphQL-and-Hot-Chocolate-79
(没有SQL后端,我想端到端地理解它,所以这有数据的内存表)。
我几乎按照演练实现了它(一些属性,例如“[UseFiltering]”无法编译,我只是暂时将它们注释掉)。
虽然我的启动看起来像这样
services.AddSingleton<IAuthorService, InMemoryAuthorService>();
services.AddSingleton<IBookService, InMemoryBookService>();
services.
AddGraphQLServer().
AddType<AuthorType>().
AddType<BookType>().
AddQueryType<GraphQL.Query>();
当我试图查询一本书的作者时,看起来很奇怪
{
books {
title
authorId
price
author {
name
surname
}
}
}
香蕉蛋糕流行抱怨
field author argument book of type BookInput! is required
(如果我不要求作者,那么一切正常)
booktype 看起来像这样(根据演练)
public class BookType : ObjectType<Book>
{
protected override void Configure(IObjectTypeDescriptor<Book> descriptor)
{
descriptor.Field(b => b.Id).Type<IdType>();
descriptor.Field(b => b.Title).Type<StringType>();
descriptor.Field(b => b.Price).Type<DecimalType>();
descriptor.Field<AuthorResolver>(t => t.GetAuthor(default, default));
}
}
作者解析器看起来像这样
public class AuthorResolver
{
private readonly IAuthorService _authorService;
public AuthorResolver([Service]IAuthorService authorService)
{
_authorService = authorService;
}
public Author GetAuthor(Book book, IResolverContext ctx)
{
return _authorService.GetAll().Where(a => a.Id == book.AuthorId).FirstOrDefault();
}
}
同样,按照演练。
我基本上理解错误,但我不明白这是怎么回事,不知何故,“书”父级必须进入 AuthorResolver 上的 GetAuthor 方法....我遗漏了一些魔法,或者 v11 缺少一些魔法。
P.S.
我更喜欢声明式类型化的表达式,而不是反身魔法...所以也许我遗漏了什么
问题是我的 AuthorResolver 上的 GetAuthor 方法缺少“Parent”属性,无法触发一些魔法....
public Author GetAuthor([Parent]Book book, IResolverContext ctx)
{
return _authorService.GetAll().Where(a => a.Id == book.AuthorId).FirstOrDefault();
}
理想情况下,我想删除这个自定义属性魔法。
实际上,当前版本 11.0.9 不需要 [Parent] 属性。我特别检查了解析器 class。但在下面的示例中,我删除了解析器,因为在您的情况下使用它太冗长了。另外,我删除了 Book 参数以显示从解析器上下文获取该参数的方法。
using System.Linq;
using HotChocolate.Resolvers;
using HotChocolate.Types;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace Ademchenko.GraphQLWorkshop
{
public class Author
{
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
}
public class Book
{
public int Id { get; set; }
public string Title { get; set; }
public int AuthorId { get; set; }
public decimal Price { get; set; }
}
public interface IAuthorService { IQueryable<Author> GetAll(); }
public interface IBookService { IQueryable<Book> GetAll(); }
public class InMemoryAuthorService : IAuthorService
{
private readonly Author[] _staticAuthors = {
new Author {Name = "FooAuthor", Surname = "FooSurname", Id = 1},
new Author {Name = "BarAuthor", Surname = "BarSurname", Id = 2},
};
public IQueryable<Author> GetAll() => _staticAuthors.AsQueryable();
}
public class InMemoryBookService : IBookService
{
private readonly Book[] _staticBooks = {
new Book {Id = 11, Title = "FooBook", AuthorId = 1, Price = 10.2m},
new Book {Id = 22, Title = "BarBook", AuthorId = 2, Price = 20.2m},
};
public IQueryable<Book> GetAll() => _staticBooks.AsQueryable();
}
public class Query
{
public IQueryable<Book> GetBooks(IResolverContext ctx) => ctx.Service<IBookService>().GetAll();
}
public class BookType : ObjectType<Book>
{
protected override void Configure(IObjectTypeDescriptor<Book> descriptor)
{
descriptor.Field(b => b.Id).Type<IdType>();
descriptor.Field("author").Resolve((ctx, ct) => ctx.Service<IAuthorService>().GetAll().FirstOrDefault(a => a.Id == ctx.Parent<Book>().AuthorId));
}
}
public class Startup
{
public IConfiguration Configuration { get; }
public Startup(IConfiguration configuration) => Configuration = configuration;
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSingleton<IAuthorService, InMemoryAuthorService>();
services.AddSingleton<IBookService, InMemoryBookService>();
services.AddGraphQLServer()
.AddQueryType<Query>()
.AddType<BookType>();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) => app.UseRouting().UseEndpoints(endpoints => endpoints.MapGraphQL());
}
}
这是一个完整的示例,所以如果您向端点发出以下请求:
{
books
{
id,
title
authorId
author
{
id
name
}
}
}
您将获得:
{
"data": {
"books": [
{
"id": "11",
"title": "FooBook",
"authorId": 1,
"author": {
"id": 1,
"name": "FooAuthor"
}
},
{
"id": "22",
"title": "BarBook",
"authorId": 2,
"author": {
"id": 2,
"name": "BarAuthor"
}
}
]
}
}