温馨提示:本文翻译自stackoverflow.com,查看原文请点击:sql - setting up a one to many relationship for a self referencing table
nestjs orm postgresql sql typeorm

sql - 为自引用表建立一对多关系

发布于 2020-05-12 11:26:46

我有一个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:

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

  • 传递undefinedsuccessorId

    该代码然后可以正常工作,但不会successorIdnull那时创建该列在数据库中根本不存在。

  • id传递相同的ID successorId(应该可以):

    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不是一个函数

查看更多

提问者
Question3r
被浏览
3
D.Zotov 2020-02-27 09:39

请尝试此解决方案

@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关系的更多信息

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

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

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