使用 type-graphql typeorm 和 dataloader 处理一对多的最佳方法

Posted

技术标签:

【中文标题】使用 type-graphql typeorm 和 dataloader 处理一对多的最佳方法【英文标题】:Best way to handle one-to-many with type-graphql typeorm and dataloader 【发布时间】:2020-12-19 02:52:41 【问题描述】:

我正在尝试找出使用 type-graphql 和 typeorm 与 postgresql db 处理一对多关系的最佳方法(使用带有 express 的 apollo 服务器)。我有一个与课程表具有一对多关系的用户表。我目前处理此问题的方式是使用@RelationId 字段创建一列userCourseIds,然后使用@FieldResolver 和dataloader 批量获取属于该用户的课程。我的问题是使用@RelationId 字段,无论我是否实际查询userCourses,都会进行单独的查询来获取relationids。有没有办法在不进行额外查询的情况下处理这个问题,或者有更好的方法来处理一对多关系?

关系的用户方:

@OneToMany(() => Course, (course) => course.creator,  cascade: true )
userCourses: Course[];
@RelationId((user: User) => user.userCourses)
userCourseIds: string;

课程方面的关系:

@Field()
@Column()
creatorId: string;

@ManyToOne(() => User, (user) => user.userCourses)
creator: User;

userCourses 字段解析器:

@FieldResolver(() => [Course],  nullable: true )
async userCourses(@Root() user: User, @Ctx()  courseLoader : MyContext) 
  const userCourses = await courseLoader.loadMany(user.userCourseIds);
  return userCourses;

【问题讨论】:

【参考方案1】:

userCourses 字段可以使用type-graphql-datalaoader 提供的@TypeormLoader 装饰器编写如下。

@ObjectType()
@Entity()
class User 
  ...

  @Field((type) => [Course])
  @OneToMany(() => Course, (course) => course.creator,  cascade: true )
  @TypeormLoader((course: Course) => course.creatorId,  selfKey: true )
  userCourses: Course[];


@ObjectType()
@Entity()
class Course 
  ...

  @ManyToOne(() => User, (user) => user.userCourses)
  creator: User;

  @RelationId((course: Course) => course.creator)
  creatorId: string;

由于省略了userCourseIds,因此不再发出其他查询。虽然creatorId@RelationId 存在,但它不会发出额外的查询,因为实体有自己的值。

更新:2021 年 6 月

@TypeormLoader 不再需要参数。因此,如果愿意,@RelationId 可以完全省略。

【讨论】:

@RelationId 为我进行额外查询。 关系属性是否为实体所有? @ManyToOne@OneToOne@JoinColumn 拥有 ID。 @RelationId 他们不会触发额外的查询。 GraphQL 数据加载器如何与 @RelationId 一起工作?我认为它被忽略了。保证 N+1 期 在上述情况下,creatorId 不会触发额外的查询,因为它是针对@ManyToOne 属性的。 @TypeormLoaderuserCourses 选择所有 courses,它们在后台的 batchLoadFn 中具有 user 的 id。 @TypeormLoader 需要 course.creatorId 以便知道选择查询的条件。

以上是关于使用 type-graphql typeorm 和 dataloader 处理一对多的最佳方法的主要内容,如果未能解决你的问题,请参考以下文章

对 Type-graphql 和 Typeorm 实体中的外键字段使用 ID 标量类型在语义上是不是正确?

如何将“typeorm”模型转换为 graphql 有效负载?

type-graphql 找不到模块“类验证器”异常

如何在typeorm中查找id的数组属性包含某个id的实体

在 TypeORM 与 GraphQL 的多对多关系上使用数据加载器,查询多对多

无法确定名为参数的 GraphQL 输入类型