今天,我们引入两个新的实体来处理客户与订单。客户与订单之间是一对多的关系,一个客户可以拥有一个或者多个订单,反过来,一个订单只能被某个客户所拥有。

可以按照 Engity Framework 的约定配置实体之间的关系。 如果某个实体拥有一个第二个实体的集合属性,Entity Framework 会自动创建一对多的关系。该属性被称为导航属性

在 Customer 实体中有一个 Orders 属性,作为集合类型的导航属性。

Customer.cs

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.cs

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; }
}

一旦定义了所有需要的关系,就可以使用 dotnet CLI 创建一个 migration 然后更新数据库。

dotnet ef migrations add OneToManyRelationship
dotnet ef database update

我们还需要创建两个新的 ObjectGraphType 。

OrderType.cs

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

为了暴露两个新的端点,还需要在 InventoryQuery 中注册这两个类型。

InventoryQuery.cs

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

在后台的数据仓库中,还需要提供相应的数据访问方法。

DataStore.cs

public async Task <IEnumerable<Order>> GetOrdersAsync() {
return await _applicationDbContext.Orders.AsNoTracking().ToListAsync();
} public async Task <IEnumerable<Customer>> GetCustomersAsync() {
return await _applicationDbContext.Customers.AsNoTracking().ToListAsync();
} public async Task <Customer> GetCustomerByIdAsync(int customerId) {
return await _applicationDbContext.Customers.FindAsync(customerId);
} public async Task <IEnumerable<Order>> GetOrdersByCustomerIdAsync(int customerId) {
return await _applicationDbContext.Orders.Where(o => o.CustomerId == customerId).ToListAsync();
}

同时,我们还增加两个方法用于创建 Customer 和 Order,

public async Task<Order> AddOrderAsync(Order order)
{
var addedOrder = await _applicationDbContext.Orders.AddAsync(order);
await _applicationDbContext.SaveChangesAsync();
return addedOrder.Entity;
} public async Task<Customer> AddCustomerAsync(Customer customer)
{
var addedCustomer = await _applicationDbContext.Customers.AddAsync(customer);
await _applicationDbContext.SaveChangesAsync();
return addedCustomer.Entity;
}

在上一篇 Blog 中,我们创建过 InputObjectGraphType 用于 Item 的创建,与其类似,我们也需要为 Customer 和 Order 创建对应的 InputObjectGraph。

OrderInputType.cs

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

CustomerInputType.cs

public class CustomerInputType : InputObjectGraphType {
public CustomerInputType()
{
Name = "CustomerInput";
Field<NonNullGraphType<StringGraphType>>("name");
Field<NonNullGraphType<StringGraphType>>("billingAddress");
}
}

最后,我们需要注册所有新的的类型到 DI 系统中。在 Startup 的 ConfigureServices 方法中如下注册。

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

现在,如果您运行应用,将会看到如下的错误信息:

"No parameterless constructor defined for this object."

通过调查 graphql-dotnet,我发现了这个问题:issue

对于当前的方案, Schema 的构造函数注入不能工作。DI 系统可以获取类型一次,但是不能对该对象链的子级再次获取。简单来说,如果在 InventoryQuery 中通过构造函数注入了 IDataSource 一次 ,但是,你不能在其他的 Graph Type 构造函数中注入;例如 CustomerType。但是,这不是我们期望的行为,因此,使用 IDependencyResolver,在 DI 系统中注册 IDependencyResolver,并确保提供一个有限的生命周期。

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

需要在 InventorySchemacs 中做一点修改,修改代码,在构造函数中注入 IDependencyResolver。

InventorySchema.cs

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

现在,重新运行应用,并验证你可以访问新增加的字段。

GraphQL Part VIII: 使用一对多查询的更多相关文章

  1. mybatis0205 一对多查询 复杂

    查询所有用户信息,关联查询订单及订单明细信息及商品信息,订单明细信息中关联查询商品信息 1.1sql 主查询表:用户信息 关联查询:订单.订单明细,商品信息 SELECT orders.*, user ...

  2. mybatis0204 一对多查询

    查询所有订单信息及订单下的订单明细信息. sql语句 主查询表:订单表 关联查询表:订单明细 SELECT orders.*, user.username, user.sex , orderdetai ...

  3. Mybatis一对多查询得不到多方结果

    一对多查询:一个年级对应多个学生,现在要查询年级(带学生)信息. 查询结果: [main] INFO com.java1234.service.GradeTest - 查询年级(带学生)[main] ...

  4. 非关心数据库无法进行连表查询 所以我们需要在进行一对多查询时候 无法满足 因此需要在"1"的一方添加"多"的一方的的id 以便用于进行连表查询 ; 核心思想通过id进行维护与建文件

     非关心数据库无法进行连表查询 所以我们需要在进行一对多查询时候 无法满足 因此需要在"1"的一方添加"多"的一方的的id 以便用于进行连表查询 ; 核心思想通 ...

  5. flask的orm框架(SQLAlchemy)-一对多查询以及多对多查询

    一对多,多对多是什么? 一对多.例如,班级与学生,一个班级对应多个学生,或者多个学生对应一个班级. 多对多.例如,学生与课程,可以有多个学生修同一门课,同时,一门课也有很多学生. 一对多查询 如果一个 ...

  6. sql 一对多查询

    1. 一对多查询 查询departmentinfo字典下所有部门的人员数量 select * from departmentinfo a left join (select count(*) User ...

  7. mybatis的一对一,一对多查询,延迟加载,缓存介绍

    一对一查询 需求 查询订单信息关联查询用户信息 sql语句 /*通过orders关联查询用户使用user_id一个外键,只能关联查询出一条用户记录就可以使用内连接*/ SELECT orders.*, ...

  8. mybatis由浅入深day02_3一对多查询

    3 一对多查询 3.1 需求(查询订单及订单明细的信息) 查询订单及订单明细的信息. 3.2 sql语句 确定主查询表:订单表 确定关联查询表:订单明细表 在一对一查询基础上添加订单明细表关联即可. ...

  9. Excel一对多查询(index+small+if)

    一.学习 一对多查询模式化数组公式: =INDEX(区域,SMALL(IF(条件,行号数组,4^8),ROW(A1))) 三键齐按(ctrl+shift+回车) 在具有多个符合条件的情况下,提取和匹配 ...

  10. hibernate一对多查询

    一对多查询 1,同时添加老师和学生案例 在进行具有关联关系的对象同时添加时 首先绑定对像间的关系 ---将多方关联一方 ---将一方关联多方 然后全部添加 备注: 1,保存老师对象时, 由于设置了学生 ...

随机推荐

  1. iOS 14 UIDatePicker适配问题,使用老的选择器样式

    iOS 14 UIDatePicker 在 13.4 新增了2个属性如下 @property (nonatomic, readwrite, assign) UIDatePickerStyle pref ...

  2. otdolist 案例

    1. 渲染默认任务 2. 回车添加任务 3. 删除任务 4. 底部任务数量 5.  tab栏切换 6. tab切换显示不同任务 7. 清除已完成的任务 8.  头部全选 9. 删除任务

  3. 云原生周刊:HashiCorp Vault 1.14 发布 | 2023.6.26

    开源项目推荐 Helmfile Helmfile 是一个开源工具,使用 Helm charts 简化复杂应用程序的部署.它提供了一种声明性的方式来定义 Kubernetes 资源的期望状态,并管理 H ...

  4. KubeSphere 社区双周报 | KubeKey v3.0.7 发布 | 2023-02-03

    KubeSphere 从诞生的第一天起便秉持着开源.开放的理念,并且以社区的方式成长,如今 KubeSphere 已经成为全球最受欢迎的开源容器平台之一.这些都离不开社区小伙伴的共同努力,你们为 Ku ...

  5. 墙裂建议收藏,100道Python练手题目

    墙裂建议收藏,100道Python练手题目 目录** 实例001:数字组合 实例002:"个税计算" 实例003:完全平方数 实例004:这天第几天 实例005:三数排序 实例00 ...

  6. Webpack热加载显示 'Cannot get /' 解决办法

    安装webpack-dev-server后,用 npm 打包运行,打开后显示 'Cannot get /' : 需要在webpack.config.js的devServer中添加以下代码: 现在再次运 ...

  7. dotnet core微服务框架Jimu介绍

    jimu是一个基于.Net6.0 简单易用的微服务框架,参考了很多开源库以及想法,使用了大量的开源库(如 DotNetty, consul.net, Flurl.Http, Json.net, Log ...

  8. manim边做边学--通用三维坐标系

    ThreeDAxes是Manim中用于创建三维坐标系的类. 在数学.物理和工程等领域,三维坐标系的绘制是非常重要的. ThreeDAxes使得用户能够在动画中直观地展示三维空间中的对象和关系,从而提高 ...

  9. 解决DDD最大难题-如何划分领域

    本文书接上回<反DDD模式之"复用">,关注公众号(老肖想当外语大佬)获取信息: 最新文章更新: DDD框架源码(.NET.Java双平台): 加群畅聊,建模分析.技术 ...

  10. “地表最强”人形机器人亮相:视觉&语音推理能力

    Figure 02配备了机载的视觉语言模型(VLM),使其能够进行快速的常识性视觉推理. 相关: https://mbd.baidu.com/newspage/data/landingsuper?co ...