ASP.NET Core中使用GraphQL - 第八章 在GraphQL中处理一对多关系

![](https://img2018.cnblogs.com/blog/65831/201811/65831-20181112222346724-1486350176.jpg) ASP.NET Core中使用GraphQL - [ASP.NET Core中使用GraphQL - 第一章 Hello World](https://www.cnblogs.com/lwqlun/p/9907127.html) - [ASP.NET Core中使用GraphQL - 第二章 中间件](https://www.cnblogs.com/lwqlun/p/9910953.html) - [ASP.NET Core中使用GraphQL - 第三章 依赖注入](https://www.cnblogs.com/lwqlun/p/9918006.html) - [ASP.NET Core中使用GraphQL - 第四章 GrahpiQL](https://www.cnblogs.com/lwqlun/p/9925542.html) - [ASP.NET Core中使用GraphQL - 第五章 字段, 参数, 变量](https://www.cnblogs.com/lwqlun/p/9926315.html) - [ASP.NET Core中使用GraphQL - 第六章 使用EF Core作为持久化仓储](https://www.cnblogs.com/lwqlun/p/9937468.html ) - [ASP.NET Core中使用GraphQL - 第七章 Mutation](https://www.cnblogs.com/lwqlun/p/9943372.html) --- 到目前为止我们一直在使用GraphQL操作单个实体。在本篇博文中,我们将使用GraphQL操作实体集合。 这里我们使用的场景是处理一个顾客的所有订单,顾客和订单之间的关系是一对多。一个顾客可以有多个订单,相应的一个订单只属于一个顾客。 ### 数据库修改 下面我们首先创建2个新的类Customer和Order。 ##### Customer ```c# public class Customer { public int CustomerId { get; set; } public string Name { get; set; } public string BillingAddress { get; set; } public IEnumerable Orders { get; set; } } ``` ##### Order ```c# public class Order { public int OrderId { get; set; } public string Tag { get; set; } public DateTime CreatedAt { get; set; } public Customer Customer { get; set; } public int CustomerId { get; set; } } ``` 然后我们修改ApplicationDbContext类,在OnModelCreating配置一下表的主外键。 ```c# modelBuilder.Entity() .HasKey(p => p.CustomerId); modelBuilder.Entity().HasMany(p => p.Orders) .WithOne() .HasForeignKey(p => p.CustomerId); modelBuilder.Entity().HasKey(p => p.OrderId); ``` 最后我们使用如下命令创建迁移并更新数据库 ``` dotnet ef migrations add OneToManyRelationship dotnet ef database update ``` 至此数据库修改完成。 ### 添加GraphQL代码 下面我们需要添加GraphQL针对Customer和Order表的字段配置。 ##### OrderType ```c# public class OrderType: ObjectGraphType { public OrderType(IDataStore dataStore) { Field(o => o.Tag); Field(o => o.CreatedAt); Field () .Name("Customer") .ResolveAsync(ctx => { return dataStore.GetCustomerByIdAsync(ctx.Source.CustomerId); }); } } ``` ##### CustomerType.cs ```c# public class CustomerType: ObjectGraphType { public CustomerType(IDataStore dataStore) { Field(c => c.Name); Field(c => c.BillingAddress); Field

, IEnumerable> () .Name("Orders") .ResolveAsync(ctx => { return dataStore.GetOrdersByCustomerIdAsync(ctx.Source.CustomerId); }); } } ``` 为了查询所有的顾客和订单,我们还需要暴露出2个新的节点。所以我们修改在InventoryQuery构造函数中添加如下代码: ##### InventoryQuery ```c# Field

, IEnumerable>() .Name("Orders") .ResolveAsync(ctx => { return dataStore.GetOrdersAsync(); }); Field

, IEnumerable>() .Name("Customers") .ResolveAsync(ctx => { return dataStore.GetCustomersAsync(); }); ``` 然后我们需要在IDataStore中定义6个新的方法,并在DataStore中实现它们。 ##### IDataStore ```c# Task> GetOrdersAsync(); Task> GetCustomersAsync(); Task GetCustomerByIdAsync(int customerId); Task> GetOrdersByCustomerIdAsync(int customerId); Task AddOrderAsync(Order order); Task AddCustomerAsync(Customer customer); ``` ##### DataStore ```c# public async Task> GetOrdersAsync() { return await _context.Orders .AsNoTracking() .ToListAsync(); } public async Task> GetCustomersAsync() { return await _context.Customers .AsNoTracking() .ToListAsync(); } public async Task GetCustomerByIdAsync(int customerId) { return await _context.Customers .FindAsync(customerId); } public async Task> GetOrdersByCustomerIdAsync(int customerId) { return await _context.Orders .Where(o => o.CustomerId == customerId) .ToListAsync(); } public async Task AddOrderAsync(Order order) { var addedOrder = await _context.Orders.AddAsync(order); await _context.SaveChangesAsync(); return addedOrder.Entity; } public async Task AddCustomerAsync(Customer customer) { var addedCustomer = await _context.Customers.AddAsync(customer); await _context.SaveChangesAsync(); return addedCustomer.Entity; } ``` 添加完以上代码之后,我们就需要定义添加订单和顾客的输入类型了。还记得在上一章中我们如何添加货物的么?我们添加了一个ItemInputType类,定义了添加货物需要收集的字段,所以这里同理,我们也需要为订单和顾客定义对应的InputObjectGraphType。 ##### OrderInputType ```c# public class OrderInputType : InputObjectGraphType { public OrderInputType() { Name = "OrderInput"; Field>("tag"); Field>("createdAt"); Field>("customerId"); } } ``` ##### CustomerInputType ```c# public class CustomerInputType : InputObjectGraphType { public CustomerInputType() { Name = "CustomerInput"; Field>("name"); Field>("billingAddress"); } } ``` 当前添加以上代码之后,我们还需要在Startup类中注册这几个新类型 ```c# public void ConfigureServices(IServiceCollection services) { .... .... services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); } ``` 如果现在启动项目,你会得到以下错误 ``` Failed to call Activator.CreateInstance. Type: chapter1.OrderType ``` 这里的问题是在InventorySchema构造函数中的注入没起作用, 原因是GraphQL在解决依赖的时候,只能处理一层, 这里OrderType和CustomerType是2层的关系。如果想解决这个问题,我们需要在Startup中再注册一个依赖解决器。 ```c# services.AddScoped(s => new FuncDependencyResolver(s.GetRequiredService)); ``` 修改完成之后我们还需要修改InventorySchema, 在构造函数中将依赖解决器注入。 ```c# public class InventorySchema: Schema { public InventorySchema(IDependencyResolver resolver): base(resolver) { Query = resolver.Resolve(); Mutation = resolver.Resolve(); } } ``` 现在再次启动项目,程序不报错了。 ### 最终效果 下面我们首先创建一个Customer ![](https://img2018.cnblogs.com/blog/65831/201811/65831-20181112222412988-549830715.png) 然后我们继续创建2个Order ![](https://img2018.cnblogs.com/blog/65831/201811/65831-20181112222419160-1458276502.png) ![](https://img2018.cnblogs.com/blog/65831/201811/65831-20181112222423456-1834692302.png) 最后我们来查询一下刚才创建的数据是否存在 ![](https://img2018.cnblogs.com/blog/65831/201811/65831-20181112222429836-2075628975.png) 数据读取正确,这说明我们的数据添加成功了。 [本文源代码: https://github.com/lamondlu/GraphQL_Blogs/tree/master/Part%20VIII](https://github.com/lamondlu/GraphQL_Blogs/tree/master/Part%20VIII)

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpyzgd.html