zoukankan      html  css  js  c++  java
  • ASP.NET Core中使用GraphQL

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

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

    数据库修改#

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

    Customer
    Copy
    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
    Copy
    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配置一下表的主外键。

    Copy
    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);

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

    Copy
    dotnet ef migrations add OneToManyRelationship  
    dotnet ef database update 

    至此数据库修改完成。

    添加GraphQL代码#

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

    OrderType
    Copy
    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
    Copy
    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
    Copy
    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
    Copy
    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
    Copy
    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
    Copy
    public class OrderInputType : InputObjectGraphType {  
        public OrderInputType()
        {
            Name = "OrderInput";
            Field<NonNullGraphType<StringGraphType>>("tag");
            Field<NonNullGraphType<DateGraphType>>("createdAt");
            Field<NonNullGraphType<IntGraphType>>("customerId");
        }
    }
    CustomerInputType
    Copy
    public class CustomerInputType : InputObjectGraphType {  
        public CustomerInputType()
        {
            Name = "CustomerInput";
            Field<NonNullGraphType<StringGraphType>>("name");
            Field<NonNullGraphType<StringGraphType>>("billingAddress");
        }
    }

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

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

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

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

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

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

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

    Copy
    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

  • 相关阅读:
    Code基础——2.排序
    设计模式——4.装饰模式
    Shader笔记——1.光照基础
    C#笔记——7.序列化与反序列化
    C#笔记——6.反射与特性
    lua小技巧记录--新建对象时重置元表
    发现的lua小技巧记录--在:方法中使用self的技巧
    lua版pureMVC框架使用分析
    在xlua中使用DoTween动画插件
    Unity工程性能优化学习笔记
  • 原文地址:https://www.cnblogs.com/lhxsoft/p/11903567.html
Copyright © 2011-2022 走看看