TypeORM @OneToOne一对一关系新增用户同步插入关联表方案
问题描述
现有三张通过TypeORM @OneToOne 装饰器定义一对一关联的数据表:user(用户主表)、userCareerProfile(用户职业资料表)、userPersonalProfile(用户个人资料表),各实体定义如下:
User 实体
@Entity({ name: 'users' }) export class User extends AbstractEntity { @Column({ unique: true }) email: string; @Column({ type: 'varchar', length: 50 }) full_name: string; @OneToOne(() => UserPersonalProfile, (details) => details.user) personal_details: UserPersonalProfile; @OneToOne(() => UserCareerProfile, (career) => career.user) career_profile: UserCareerProfile; }
UserPersonalProfile 个人资料实体
@Entity() export class UserPersonalProfile extends AbstractEntity { @Column({ type: 'varchar', length: 20, nullable: true }) date_of_birth: string; @Column({ type: 'varchar', length: 200, nullable: true }) address: string; ..... @OneToOne(() => User, (user) => user.personal_details, { onDelete: 'CASCADE', }) @JoinColumn({ name: 'user_id' }) user: User; }
UserCareerProfile 职业资料实体
@Entity() export class UserCareerProfile extends AbstractEntity { @Column({ type: 'varchar', length: 100, nullable: true }) job_role: string; @Column({ type: 'varchar', length: 100, nullable: true }) work_location: string; ..... @OneToOne(() => User, (user) => user.career_profile, { onDelete: 'CASCADE', }) @JoinColumn({ name: 'user_id' }) user: User; }
当前调用创建用户方法时,仅users主表成功插入数据行,userCareerProfile、userPersonalProfile两张关联表未生成对应记录。现有服务层createUser方法实现如下:
public async createUser(userAttrs: Partial<User>): Promise<User> { const user = await this._usersRepository.save( this._usersRepository.create({ ...userAttrs, }), ); return user; }
需要实现:创建用户主表记录后,同步向两张关联表插入对应用户的关联数据。
解决方案
问题核心原因是TypeORM默认不会自动持久化关联表数据,既没有在主表关联配置中开启级联规则,保存逻辑中也没有手动初始化关联表实例,两种可直接落地的实现方案如下:
方案1:开启级联保存(代码最简洁)
在User主表的@OneToOne装饰器中添加cascade: true配置,后续保存User实体时,TypeORM会自动持久化挂载的关联实体。
- 修改User实体的关联配置:
@Entity({ name: 'users' }) export class User extends AbstractEntity { // 其余原有字段保持不变 ..... @OneToOne(() => UserPersonalProfile, (details) => details.user, { cascade: true }) personal_details: UserPersonalProfile; @OneToOne(() => UserCareerProfile, (career) => career.user, { cascade: true }) career_profile: UserCareerProfile; }
- 调整
createUser方法,创建用户时同步初始化两个关联表的空实例:
public async createUser(userAttrs: Partial<User>): Promise<User> { const user = this._usersRepository.create({ ...userAttrs, // 初始化关联表空记录,字段会自动按nullable规则存储null值 personal_details: new UserPersonalProfile(), career_profile: new UserCareerProfile() }); // 保存时自动级联插入两张关联表数据,自动绑定user_id外键 return this._usersRepository.save(user); }
如果创建用户时需要同步传入个人/职业资料字段值,直接在初始化关联实例时传入对应字段即可,TypeORM会自动完成字段赋值。
方案2:手动分表保存(逻辑更可控)
如果不希望开启全局级联配置,也可以在保存主表用户后,手动调用两个关联表的仓储层插入对应记录:
// 先在服务构造函数中注入两个关联表的Repository constructor( @InjectRepository(User) private readonly _usersRepository: Repository<User>, @InjectRepository(UserPersonalProfile) private readonly _personalProfileRepository: Repository<UserPersonalProfile>, @InjectRepository(UserCareerProfile) private readonly _careerProfileRepository: Repository<UserCareerProfile> ) {} public async createUser(userAttrs: Partial<User>): Promise<User> { // 第一步:保存主表用户记录 const user = await this._usersRepository.save( this._usersRepository.create({ ...userAttrs, }), ); // 第二步:插入个人资料记录,绑定新生成的用户ID await this._personalProfileRepository.save( this._personalProfileRepository.create({ user: user, // 可在此处传入个人资料初始字段 }) ) // 第三步:插入职业资料记录,绑定新生成的用户ID await this._careerProfileRepository.save( this._careerProfileRepository.create({ user: user, // 可在此处传入职业资料初始字段 }) ) // 第四步:查询返回带关联数据的完整用户信息 return this._usersRepository.findOne({ where: { id: user.id }, relations: ['personal_details', 'career_profile'] }) }
注意:使用手动分表保存方案时,建议把三个数据库操作包裹在事务中执行,避免主表插入成功但关联表插入失败导致的数据不一致问题。
内容的提问来源于stack exchange,提问作者RAHUL KUNDU
相关产品推荐
相关产品推荐

