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

Que*_*n3r 6 sql postgresql orm typeorm nestjs

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

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

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

通过创建新项目时

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

有多种情况我必须处理。

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

    这不会抛出错误。它只是覆盖现有实体。

  • 传递undefinedsuccessorId

    然后代码工作正常,但它不会创建一个successorIdnull。该列根本不存在于数据库中。

  • idand传递相同的 id successorId(这应该是可能的):

    TypeORM 抛出错误

    类型错误:无法读取未定义的属性“joinColumns”

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

    我收到与上述相同的错误

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

    我收到与上述相同的错误

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

  • 一个项目可能有一个继任者
  • 一个项目可以是多个项目的继承者

如果有人可以提供帮助,那就太棒了!


更新

我也试过这个

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

但是每当我想调用该createProject方法时,我都会收到此错误

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

和这个

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

但后来我收到了这个错误

类型错误:relatedEntities.forEach 不是函数

D.Z*_*tov 5

请试试这个解决方案

@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;
}
Run Code Online (Sandbox Code Playgroud)

public successor?: Project;- 属性用于建立实体(在本例中为同一实体)之间的关系。相关实体必须指定为属性类型,因为 TypeORM 使用此类型来确定目标实体并构建关系元数据。您可以在此处阅读有关 TypeORM 关系的更多信息

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

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

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