如何在TypeORM中解决MySQL管理员与密码表的循环ID引用?
问题描述
现有两张MySQL表:
administrators表:包含id、passwordId、createTime字段passwords表:包含id、currentPassword、oldPassword、olderPassword、administratorId、createTime、updateTime字段
创建管理员时需要指定passwordId,创建密码时又需要指定administratorId,陷入循环引用无法创建数据。当前使用的TypeORM实体代码如下:
@Entity("administrators") class Admin extends BaseEntity { // Changed to 'Admin' for uniqueness @PrimaryGeneratedColumn({ type: "int", name: "id", }) id: number; @Column({ type: "varchar", name: "password", select: false }) @OneToOne(() => Password, (password) => password.id) @JoinColumn({ name: "passwordId" }) // Corrected join column name password: Password; } @Entity("passwords") class Password extends BaseEntity { @PrimaryGeneratedColumn({ type: "int", name: "id" }) id: number; @Column({ type: "varchar", name: "currentPassword", length: 255 }) currentPassword: string; @Column({ type: "varchar", name: "oldPassword", length: 255, nullable: true }) oldPassword: string; @Column({ type: "varchar", name: "olderPassword", length: 255, nullable: true, }) olderPassword: string; @Column({ type: "int", name: "administratorId", transformer: fromToStringNumberTransformer, }) @OneToOne(() => Admin, (admin) => admin.id) // Corrected entity reference administratorId: number; }
之前在PHP+mysqli中可以预取下一个ID直接使用,请问在TypeORM中如何创建关联密码的管理员?
解决方法
1. 修正实体关联配置
首先需要修正实体中的关联定义,避免@Column和@OneToOne混用,同时利用TypeORM的关联级联功能处理循环依赖:
Admin实体修正
移除多余的@Column定义,由@JoinColumn自动维护外键列,并开启级联保存:
@Entity("administrators") class Admin extends BaseEntity { @PrimaryGeneratedColumn({ type: "int", name: "id" }) id: number; // 开启cascade: true,保存Admin时自动关联保存Password @OneToOne(() => Password, password => password.admin, { cascade: true }) @JoinColumn({ name: "passwordId" }) // 对应administrators表的passwordId字段 password: Password; @CreateDateColumn({ name: "createTime" }) createTime: Date; }
Password实体修正
移除单独的administratorId列定义,改为双向关联指向Admin实体:
@Entity("passwords") class Password extends BaseEntity { @PrimaryGeneratedColumn({ type: "int", name: "id" }) id: number; @Column({ type: "varchar", name: "currentPassword", length: 255 }) currentPassword: string; @Column({ type: "varchar", name: "oldPassword", length: 255, nullable: true }) oldPassword: string; @Column({ type: "varchar", name: "olderPassword", length: 255, nullable: true }) olderPassword: string; // 双向关联Admin实体,无需额外定义administratorId列 @OneToOne(() => Admin, admin => admin.password) admin: Admin; @CreateDateColumn({ name: "createTime" }) createTime: Date; @UpdateDateColumn({ name: "updateTime" }) updateTime: Date; }
2. 创建关联数据
通过级联保存,只需创建Admin和Password实例并关联,TypeORM会自动处理插入顺序,无需手动预取ID:
async function createAdminWithPassword() { // 创建密码实例 const password = new Password(); password.currentPassword = "your_hashed_password"; // 注意密码要加密存储 // 可选:设置oldPassword、olderPassword等字段 // 创建管理员实例并关联密码 const admin = new Admin(); admin.password = password; // 保存管理员,TypeORM会自动先插入Password,再插入Admin并关联外键 await admin.save(); console.log("管理员和密码创建完成:", admin.id, password.id); }
备选方案:手动控制插入顺序
如果不想使用级联,也可以手动分三步操作:
- 创建并保存Admin(暂不设置passwordId)
- 创建Password并关联已保存的Admin,保存得到passwordId
- 更新Admin的passwordId为刚生成的passwordId并保存
代码示例:
async function createAdminWithPasswordManual() { // 1. 创建并保存Admin const admin = new Admin(); await admin.save(); // 2. 创建Password并关联Admin const password = new Password(); password.currentPassword = "your_hashed_password"; password.admin = admin; await password.save(); // 3. 更新Admin的passwordId admin.password = password; await admin.save(); }
内容的提问来源于stack exchange,提问作者Islam Y-
相关产品推荐
相关产品推荐

