分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > 运营维护

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

发布时间:2023-09-06 02:22责任编辑:顾先生关键词:.NET

ASP.NET Core中使用GraphQL - 目录

  • ASP.NET Core中使用GraphQL - 第一章 Hello World
  • ASP.NET Core中使用GraphQL - 第二章 中间件
  • ASP.NET Core中使用GraphQL - 第三章 依赖注入
  • ASP.NET Core中使用GraphQL - 第四章 GrahpiQL
  • ASP.NET Core中使用GraphQL - 第五章 字段, 参数, 变量
  • ASP.NET Core中使用GraphQL - 第六章 使用EF Core作为持久化仓储
  • ASP.NET Core中使用GraphQL - 第七章 Mutation

到目前为止我们一直在使用GraphQL操作单个实体。在本篇博文中,我们将使用GraphQL操作实体集合。

这里我们使用的场景是处理一个顾客的所有订单,顾客和订单之间的关系是一对多。一个顾客可以有多个订单,相应的一个订单只属于一个顾客。

数据库修改

下面我们首先创建2个新的类CustomerOrder

Customer
public class Customer{ ???public int CustomerId { get; set; } ???public string Name { get; set; } ???public string BillingAddress { get; set; } ???public IEnumerable<Order> Orders { get; set; }}
Order
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配置一下表的主外键。

modelBuilder.Entity<Customer>() ???.HasKey(p => p.CustomerId);modelBuilder.Entity<Customer>().HasMany(p => p.Orders) ???.WithOne() ???.HasForeignKey(p => p.CustomerId);modelBuilder.Entity<Order>().HasKey(p => p.OrderId);

最后我们使用如下命令创建迁移并更新数据库

dotnet ef migrations add OneToManyRelationship ?dotnet ef database update 

至此数据库修改完成。

添加GraphQL代码

下面我们需要添加GraphQL针对CustomerOrder表的字段配置。

OrderType
public class OrderType: ObjectGraphType <Order> { ?????public OrderType(IDataStore dataStore) { ???????Field(o => o.Tag); ???????Field(o => o.CreatedAt); ???????Field <CustomerType, Customer> () ???????????.Name("Customer") ???????????.ResolveAsync(ctx => { ???????????????return dataStore.GetCustomerByIdAsync(ctx.Source.CustomerId); ???????????}); ???}}
CustomerType.cs
public class CustomerType: ObjectGraphType <Customer> { ?????public CustomerType(IDataStore dataStore) { ???????Field(c => c.Name); ???????Field(c => c.BillingAddress); ???????Field <ListGraphType<OrderType> , IEnumerable<Order>> () ???????????.Name("Orders") ???????????.ResolveAsync(ctx => { ???????????????return dataStore.GetOrdersByCustomerIdAsync(ctx.Source.CustomerId); ???????????}); ???}}

为了查询所有的顾客和订单,我们还需要暴露出2个新的节点。所以我们修改在InventoryQuery构造函数中添加如下代码:

InventoryQuery
Field<ListGraphType<OrderType>, IEnumerable<Order>>() ?????.Name("Orders") ???.ResolveAsync(ctx => ???{ ???????return dataStore.GetOrdersAsync(); ???});Field<ListGraphType<CustomerType>, IEnumerable<Customer>>() ?????.Name("Customers") ???.ResolveAsync(ctx => ???{ ???????return dataStore.GetCustomersAsync(); ???});

然后我们需要在IDataStore中定义6个新的方法,并在DataStore中实现它们。

IDataStore
Task<IEnumerable<Order>> GetOrdersAsync();Task<IEnumerable<Customer>> GetCustomersAsync();Task<Customer> GetCustomerByIdAsync(int customerId);Task<IEnumerable<Order>> GetOrdersByCustomerIdAsync(int customerId);Task<Order> AddOrderAsync(Order order);Task<Customer> AddCustomerAsync(Customer customer);
DataStore
public async Task<IEnumerable<Order>> GetOrdersAsync(){ ???return await _context.Orders ???????.AsNoTracking() ???????.ToListAsync();}public async Task<IEnumerable<Customer>> GetCustomersAsync(){ ???return await _context.Customers ???????.AsNoTracking() ???????.ToListAsync();}public async Task<Customer> GetCustomerByIdAsync(int customerId){ ???return await _context.Customers ???????.FindAsync(customerId);}public async Task<IEnumerable<Order>> GetOrdersByCustomerIdAsync(int customerId){ ???return await _context.Orders ???????.Where(o => o.CustomerId == customerId) ???????.ToListAsync();}public async Task<Order> AddOrderAsync(Order order) ?{ ???var addedOrder = await _context.Orders.AddAsync(order); ???await _context.SaveChangesAsync(); ???return addedOrder.Entity;}public async Task<Customer> AddCustomerAsync(Customer customer) ?{ ????????????var addedCustomer = await _context.Customers.AddAsync(customer); ???await _context.SaveChangesAsync(); ???return addedCustomer.Entity;}

添加完以上代码之后,我们就需要定义添加订单和顾客的输入类型了。还记得在上一章中我们如何添加货物的么?我们添加了一个ItemInputType类,定义了添加货物需要收集的字段,所以这里同理,我们也需要为订单和顾客定义对应的InputObjectGraphType

OrderInputType
public class OrderInputType : InputObjectGraphType { ?????public OrderInputType() ???{ ???????Name = "OrderInput"; ???????Field<NonNullGraphType<StringGraphType>>("tag"); ???????Field<NonNullGraphType<DateGraphType>>("createdAt"); ???????Field<NonNullGraphType<IntGraphType>>("customerId"); ???}}
CustomerInputType
public class CustomerInputType : InputObjectGraphType { ?????public CustomerInputType() ???{ ???????Name = "CustomerInput"; ???????Field<NonNullGraphType<StringGraphType>>("name"); ???????Field<NonNullGraphType<StringGraphType>>("billingAddress"); ???}}

当前添加以上代码之后,我们还需要在Startup类中注册这几个新类型

public void ConfigureServices(IServiceCollection services) ?{ ????.... ???.... ???services.AddScoped<CustomerType>(); ???services.AddScoped<CustomerInputType>(); ???services.AddScoped<OrderType>(); ???services.AddScoped<OrderInputType>();}

如果现在启动项目,你会得到以下错误

Failed to call Activator.CreateInstance. Type: chapter1.OrderType

这里的问题是在InventorySchema构造函数中的注入没起作用, 原因是GraphQL在解决依赖的时候,只能处理一层, 这里OrderTypeCustomerType是2层的关系。如果想解决这个问题,我们需要在Startup中再注册一个依赖解决器。

services.AddScoped<IDependencyResolver>(s => ????new FuncDependencyResolver(s.GetRequiredService)); ?

修改完成之后我们还需要修改InventorySchema, 在构造函数中将依赖解决器注入。

public class InventorySchema: Schema { ?????public InventorySchema(IDependencyResolver resolver): base(resolver) { ???????Query = resolver.Resolve<InventoryQuery>(); ???????Mutation = resolver.Resolve<InventoryMutation>(); ???}}

现在再次启动项目,程序不报错了。

最终效果

下面我们首先创建一个Customer

然后我们继续创建2个Order


最后我们来查询一下刚才创建的数据是否存在

数据读取正确,这说明我们的数据添加成功了。

本文源代码: https://github.com/lamondlu/GraphQL_Blogs/tree/master/Part%20VIII

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

原文地址:https://www.cnblogs.com/lwqlun/p/9949559.html

知识推荐

我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved