为自引用表设置一对多关系

时间:2020-02-23 10:48:03

标签: sql postgresql orm nestjs typeorm

我有一个Project实体,具有一个非自动生成的id字段和一个后继字段。此后继者是接下来的项目。但是也许没有后续的项目,所以它可能为空。

@Entity()
export class Project extends BaseEntity {
  @PrimaryColumn({ unique: true })
  public id: string;

  @OneToMany(() => Project, project => project.id, { nullable: true })
  public successorId?: string;
}

通过创建新项目时

public createProject(id: string, successorId?: string): Promise<Project> {
  const project: Project = new Project();
  project.id = id;
  project.successorId = successorId;
  return project.save();
}

有很多情况我需要照顾。

  • 传入一个已经存在的ID:

    这不会引发错误。它只是覆盖现有实体。

  • undefined传递successorId

    然后该代码可以正常工作,但随后不会使用successorId创建一个null列。该列在数据库中根本不存在。

  • idsuccessorId输入相同的ID(应该可以):

    TypeORM引发错误

    TypeError:无法读取未定义的属性'joinColumns'

  • 传入另一个现有项目的successorId

    我遇到与上述相同的错误

  • 传入一个不存在的项目的successorId

    我遇到与上述相同的错误

那我该如何解决呢?我认为我的实体设计似乎是错误的。基本上应该是

  • 一个项目可能有一个继任者
  • 一个项目可以成为许多项目的继任者

如果有人可以帮助,那将太棒了!


更新

我也尝试过

@OneToMany(() => Project, project => project.successorId, { nullable: true })
@Column()
public successorId?: string;

但是每当我想调用createProject方法时,都会出现此错误

QueryFailedError:“ successorId”列中的空值违反了非空值 约束

还有这个

@OneToMany(() => Project, project => project.successorId, { nullable: true })
public successorId?: string;

但随后出现此错误

TypeError:relatedEntities.forEach不是函数

1 个答案:

答案 0 :(得分:4)

请尝试此解决方案

@Entity()
export class Project extends BaseEntity {
  @PrimaryColumn({ unique: true })
  public id: string

  @Column({ nullable: true })
  public successorId?: string

  @ManyToOne(() => Project, project => project.id)
  @JoinColumn({ name: "successorId" })
  public successor?: Project
}

public successor?: Project-属性用于在实体之间建立关系(在这种情况下为相同实体)。必须将相关实体指定为属性类型,因为TypeORM使用此类型来确定目标实体并建立关系元数据。您可以阅读有关TypeORM关系here

的更多信息

public successorId?: string-属性只是一个“提取的”连接列。当您使用ManyToOne关系时,TypeORM会在数据库中自动创建一个名为propertyName + referencedColumnName的列(在这种情况下为successorId)。但是您不能在代码中使用此列,因为它仅在表中定义,而不在类中定义。并且,如果您需要在类中定义此列(以进行进一步保存或显示),则可以创建一个属性并用@Column装饰器对其进行标记。属性名称必须与表中的连接列名称相同。详细介绍here

创建具有相同ID的实体只会覆盖现有实体

这是预期的行为。当您尝试使用现有ID保存实体时,TypeORM会将其识别为更新,而不是创建