ASP.NET Core中使用GraphQL - 目錄html
到目前爲止咱們一直在使用GraphQL操做單個實體。在本篇博文中,咱們將使用GraphQL操做實體集合。git
這裏咱們使用的場景是處理一個顧客的全部訂單,顧客和訂單之間的關係是一對多。一個顧客能夠有多個訂單,相應的一個訂單隻屬於一個顧客。github
下面咱們首先建立2個新的類Customer
和Order
。數據庫
public class Customer { public int CustomerId { get; set; } public string Name { get; set; } public string BillingAddress { get; set; } public IEnumerable<Order> Orders { get; set; } }
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<Customer>() .HasKey(p => p.CustomerId); modelBuilder.Entity<Customer>().HasMany(p => p.Orders) .WithOne() .HasForeignKey(p => p.CustomerId); modelBuilder.Entity<Order>().HasKey(p => p.OrderId);
最後咱們使用以下命令建立遷移並更新數據庫async
dotnet ef migrations add OneToManyRelationship dotnet ef database update
至此數據庫修改完成。函數
下面咱們須要添加GraphQL針對Customer
和Order
表的字段配置。ui
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); }); } }
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
構造函數中添加以下代碼:code
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
中實現它們。htm
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);
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
。
public class OrderInputType : InputObjectGraphType { public OrderInputType() { Name = "OrderInput"; Field<NonNullGraphType<StringGraphType>>("tag"); Field<NonNullGraphType<DateGraphType>>("createdAt"); Field<NonNullGraphType<IntGraphType>>("customerId"); } }
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
在解決依賴的時候,只能處理一層, 這裏OrderType
和CustomerType
是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