如何保存 2 个相关的 Typeorm 实体?

How to save 2 entities that are related Typeorm?

我有一个 NestJS 项目,它有一个名为 Users 的实体。在这个实体中有关于用户的登录相关信息。我还有另一个名为 Profile 的实体,它将保存用户的姓名、图片等...

这两个实体相互关联,问题是,当用户注册时,我还没有任何个人资料信息。我怎样才能在 TypeOrm 上做到这一点?我试着只保存用户信息,但是当我创建配置文件时,它与用户无关。

谢谢

这是我的实体:

用户实体

import {
  BaseEntity,
  Column,
  Entity,
  JoinColumn,
  OneToOne,
  PrimaryGeneratedColumn,
  Unique,
} from 'typeorm';
import * as bcrypt from 'bcrypt';
import { UserProfile } from './profile/user-profile.entity';

@Entity()
@Unique(['email'])
export class User extends BaseEntity {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @Column()
  email: string;

  @Column()
  password: string;

  @Column()
  salt: string;

  async validatePassword(password: string): Promise<boolean> {
    const hash = await bcrypt.hash(password, this.salt);
    return hash === this.password;
  }

  @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })
  registration_date: Date;

  @Column({ nullable: true })
  login_method: string;

  @Column()
  role: string;

  @OneToOne(() => UserProfile, (profile) => profile.user)
  @JoinColumn()
  profile: UserProfile;
}

用户存储库(保存方法)

async newUser(authCred: AuthCredentialsDTO): Promise<User> {
    const { password } = authCred;
    const userCred = new User();
    Object.assign(userCred, authCred);
    userCred.salt = await bcrypt.genSalt();
    userCred.password = await this.hashPassword(password, userCred.salt);

    try {
      await userCred.save();
      return userCred;
    } catch (error) {
      throw new InternalServerErrorException(error);
    }
  }

配置文件实体

import { BaseEntity, Column, Entity, OneToOne, PrimaryGeneratedColumn } from 'typeorm';
import { User } from '../user.entity';

@Entity()
export class UserProfile extends BaseEntity {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @Column({ nullable: true })
  firstName: string;

  @Column({ nullable: true })
  lastName: string;

  @Column({ nullable: true })
  address: string;

  @Column({ nullable: true })
  address_comp: string;

  @Column({ nullable: true })
  city: string;

  @Column({ nullable: true })
  province_state: string;

  @Column({ nullable: true })
  postal_code: string;

  @Column({ nullable: true })
  picture: string;

  @OneToOne(() => User, (user) => user.profile)
  user: User;
}

我重写了 User 实体以简化它并删除不必要的代码。 此外,我还进行了以下更改:

  1. 直接在电子邮件栏装饰器中设置unique: true
  2. registration_date 现在是自动设置创建日期的@CreateDateColumn({ type: 'timestamp', update: false })。
  3. password 保存 salt 是一种不好的做法。参见 this
  4. profile 列中设置 cascade: true 这样当您保存 User 实体和 profile 字段时 " " 也被保存了。参见
  5. validatePassword(...)移到另一个地方。不要污染你的实体。
    1. 在您的数据库中只存储密码哈希。
    2. 要将明文密码与存储在数据库中的哈希值进行比较,请使用 bcrypt.compare(plainPassword, hashPassword) 函数。
  6. 使用 .create(...) 方法“创建” 实体实例并设置其值。

用户实体:

@Entity()
export class User extends BaseEntity {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @Column({ unique: true })
  email: string;

  @Column()
  password: string;

  @CreateDateColumn({ type: 'timestamp' })
  registration_date: Date;

  @Column({ nullable: true })
  login_method: string;

  @Column()
  role: string;

  @OneToOne(() => UserProfile, (profile) => profile.user, { cascade: true })
  @JoinColumn()
  profile: UserProfile;
}

用户存储库:

async newUser(authCred: AuthCredentialsDTO): Promise<User> {
  const entityManager = getManager();
  const { password } = authCred;

  const user = entityManager.create(User, {
    password: await hashPassword(password, await bcrypt.genSalt()),
    profile: {}
  });

  try {
    return (await entityManager.save(User, user));
  } catch (error) {
    throw new InternalServerErrorException(error);
  }
}