카테고리 없음

[Nest.js] Nest.js API 만들기 (7) - TypeORM 관계 설정(1 : 1, 1 : N, N : M)

RyanSin 2021. 11. 14. 17:02
반응형

- 지난 시간

안녕하세요. 지난 시간에는 TypeORM을 적용해 API 서버를 수정하는 시간은 가져봤습니다.

 

혹시 지난 시간 내용을 놓치고 오신 분들은 아래 링크를 통해 학습하고 오시는 걸 추천드리겠습니다.

[Nest.js] Nest.js API 만들기 (6) - TypeORM API서버 적용(CRUD)

 

[Nest.js] Nest.js API 만들기 (6) - TypeORM API서버 적용(CRUD)

- 지난 시간 안녕하세요. 지난 시간에는 TypeORM 설정 및 연결하는 방법에 대해 알아봤습니다. 혹시 놓치고 오신 분들은 아래 링크를 통해 학습하고 오시는 걸 추천드리겠습니다. [Nest.js] Nest.js API

any-ting.tistory.com

 

- 개요

이번 시간에는 TypeORM에서 관계 설정하는 방법에 대해 알아보겠습니다.

 

보통 관계를 맺는 방식은 1 : 1(일 대 일), 1 : M (일 대 다), N : M (다 대 다)로 맺습니다.

 

관계 설정시 사용되는 데코레이터는 @OneToOne, @OneToMany, @ManyToOne , @ManyToMany 가 사용됩니다.

 

1 : 1 관계 설정(User Entity & Profile Entity)

User Entity
import {
  BaseEntity,
  Column,
  Entity,
  PrimaryGeneratedColumn,
  CreateDateColumn,
  UpdateDateColumn,
  DeleteDateColumn,
  Unique,
  OneToOne,
  JoinColumn,
} from 'typeorm';
import { Profile } from './profile.entity';

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

  @Column({ type: 'varchar', length: 50, comment: '유저 아이디' })
  user_id: string;

  @Column({ type: 'varchar', length: 255, comment: '유저 비밀번호' })
  password: string;

  @Column({ type: 'varchar', length: 255, comment: 'salt' })
  salt: string;

  @Column({ type: 'varchar', length: 30, comment: '유저 이름' })
  name: string;

  @Column({ type: 'tinyint', comment: '유저 나이' })
  age: number;

  @CreateDateColumn({ name: 'create_at', comment: '생성일' })
  createdAt: Date;

  @UpdateDateColumn({ name: 'update_at', comment: '수정일' })
  updatedAt: Date;

  @DeleteDateColumn({ name: 'delete_at', comment: '삭제일' })
  deletedAt?: Date | null;

  /**
   * 1 : 1 관계 설정
   * @OneToOne -> 해당 엔티티(User) To 대상 엔티티(Profile)
   *              하나의 유저는 하나의 개인정보를 갖는다.
   */
  @OneToOne(() => Profile)
  @JoinColumn({ name: 'profile_id' })
  profile: Profile;
}

 

Profile Entity
//Enum 설정
enum STATUS {
  PAUSE = 'PAUSE',
  ACTIVE = 'ACTIVE',
}

import {
  BaseEntity,
  Column,
  Entity,
  PrimaryGeneratedColumn,
  CreateDateColumn,
  UpdateDateColumn,
  DeleteDateColumn,
} from 'typeorm';

@Entity({ name: 'profile' })
export class Profile extends BaseEntity {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @Column({
    type: 'varchar',
    length: 50,
    comment: '유저 권한(Ex: 관리자, 일반 유저 등등)',
  })
  permission: string;

  @Column({
    type: 'enum',
    enum: STATUS,
    default: STATUS.PAUSE,
    comment: '계정상태(ACTIVE, PAUSE)',
  })
  status: string;

  @Column({ type: 'tinyint', width: 1, default: 0, comment: '계정 블락 유무' })
  block: string;

  @Column({
    type: 'date',
    comment: '계정 유효기간(패키지 별 설정) Ex) 2021-12-14',
  })
  account_expired: Date;

  @Column({
    type: 'date',
    comment: '비밀번호 유효기간(주기적 업데이트) Ex) 2021-12-14',
  })
  password_expired: Date;

  @CreateDateColumn({ name: 'create_at', comment: '생성일' })
  createdAt: Date;

  @UpdateDateColumn({ name: 'update_at', comment: '수정일' })
  updatedAt: Date;

  @DeleteDateColumn({ name: 'delete_at', comment: '삭제일' })
  deletedAt?: Date | null;
}

 

두 Entity는 1 : 1 관계를 설정했습니다. User Entity에서 @OneToOne 데코레이터와 @JoinColumn 데코레이터를 확인할 수 있습니다.

 

@OneToOne 데코레이터는 말 그대로 대상 Entity(Profile)와 1 : 1 관계를 설정이며, @JoinColumn 데코레이터는 대상 Entity(Profile) 고유 아이디 값을 FK(foreign key:외래키)로 설정한다는 뜻입니다.

 

user 테이블

 

profile 테이블

 

1 : N 관계 설정 (User Entity & CompanyInformation Entity)

User Entity
import {
  BaseEntity,
  Column,
  Entity,
  PrimaryGeneratedColumn,
  CreateDateColumn,
  UpdateDateColumn,
  DeleteDateColumn,
  Unique,
  OneToOne,
  JoinColumn,
  ManyToOne,
} from 'typeorm';
import { CompanyInformation } from './company_infomation.entity';
import { Profile } from './profile.entity';

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

  @Column({ type: 'varchar', length: 50, comment: '유저 아이디' })
  user_id: string;

  @Column({ type: 'varchar', length: 255, comment: '유저 비밀번호' })
  password: string;

  @Column({ type: 'varchar', length: 255, comment: 'salt' })
  salt: string;

  @Column({ type: 'varchar', length: 30, comment: '유저 이름' })
  name: string;

  @Column({ type: 'tinyint', comment: '유저 나이' })
  age: number;

  @CreateDateColumn({ name: 'create_at', comment: '생성일' })
  createdAt: Date;

  @UpdateDateColumn({ name: 'update_at', comment: '수정일' })
  updatedAt: Date;

  @DeleteDateColumn({ name: 'delete_at', comment: '삭제일' })
  deletedAt?: Date | null;

  /**
   * 1 : 1 관계 설정
   * @OneToOne -> 해당 엔티티(User) To 대상 엔티티(Profile)
   *              하나의 유저는 하나의 개인정보를 갖는다.
   */
  @OneToOne(() => Profile)
  @JoinColumn({ name: 'profile_id' })
  profile: Profile;

  /**
   * 1 : M 관계 설정
   * @ManyToOne -> 해당 엔티티(User) To 대상 엔티티(CompanyInformation)
   *               여러 유저는 하나의 회사에 소속
   */
  @ManyToOne(
    () => CompanyInformation,
    (comapnyInformation) => comapnyInformation.userId,
  )
  @JoinColumn({ name: 'company_id' })
  companyInformation: CompanyInformation;
}

 

CompanyInformation Entity
import { IsEmail } from 'class-validator';
import {
  BaseEntity,
  Column,
  Entity,
  PrimaryGeneratedColumn,
  CreateDateColumn,
  UpdateDateColumn,
  DeleteDateColumn,
  OneToMany,
} from 'typeorm';
import { User } from './user.entity';

@Entity({ name: 'company_information' })
export class CompanyInformation extends BaseEntity {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  //length 설정하지 않으면 기본 255 길이 설정
  @Column({
    type: 'varchar',
    comment: '회사 이름',
  })
  hospital_name: string;

  @IsEmail()
  @Column({
    type: 'varchar',
    length: 50,
    comment: '회사 이메일',
  })
  email: string;

  @Column({ type: 'varchar', length: 50, comment: '회사 관리자 이름' })
  name: string;

  @Column({
    type: 'varchar',
    length: 72,
    comment: '회사 전화번호',
  })
  phone: string;

  @Column({
    type: 'varchar',
    length: 72,
    comment: '팩스번호',
  })
  fax: string;

  @Column({
    type: 'varchar',
    length: 45,
    name: 'business_number',
    comment: '사업자등록 번호',
  })
  business_number: string;

  @Column({
    type: 'text',
    comment: '주소',
  })
  address: string;

  @Column({
    type: 'text',
    comment: '상세주소',
  })
  detail_address: string;

  @CreateDateColumn({ name: 'create_at', comment: '생성일' })
  createdAt: Date;

  @UpdateDateColumn({ name: 'update_at', comment: '수정일' })
  updatedAt: Date;

  @DeleteDateColumn({ name: 'delete_at', comment: '삭제일' })
  deletedAt?: Date | null;

  /**
   * 1 : M 관계 설정
   * @OneToMany -> 해당 엔티티(CompanyInformation) To 대상 엔티티 (User)
   */
  @OneToMany(() => User, (user) => user.id)
  userId: User[];
}

 

1 : N 관계를 설정할 때 @OneToMany & @ManyToMany라고 위에서 말씀드렸습니다.

 

하나의 회사는 여러 임직원을 둘 수 있습니다. 그렇기 때문에 CompanyInformation Entity에는 @OneToMany 데코레이터로 설정을 했으며, User Entity는 여러 대상이 될 수 있기 때문에 @ManyToOne으로 설정했습니다.

 

User Entity는 특정 회사에 소속되기 때문에 @JoinColumn 데코레이터를 사용해 CompanyInformation에 외례키를 갖습니다

 

user 테이블

 

company_information 테이블

 

N : M 관계 설정(Borad Entity & Category Entity)

Board Entity
import {
  BaseEntity,
  Column,
  Entity,
  PrimaryGeneratedColumn,
  CreateDateColumn,
  UpdateDateColumn,
  DeleteDateColumn,
  ManyToMany,
  JoinTable,
} from 'typeorm';
import { Category } from './category.entity';

@Entity({ name: 'board' })
export class Board extends BaseEntity {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  //length 설정하지 않으면 기본 255 길이 설정
  @Column({
    type: 'varchar',
    comment: '게시글 이름',
  })
  name: string;

  @Column({
    type: 'varchar',
    length: 4000,
    comment: '게시글 내용',
  })
  content: string;

  @Column({
    type: 'int',
    default: 0,
    comment: '게시글 조회수',
  })
  view: number;

  @CreateDateColumn({ name: 'create_at', comment: '생성일' })
  createdAt: Date;

  @UpdateDateColumn({ name: 'update_at', comment: '수정일' })
  updatedAt: Date;

  @DeleteDateColumn({ name: 'delete_at', comment: '삭제일' })
  deletedAt?: Date | null;

  @ManyToMany(() => Category)
  @JoinTable()
  category: Category;
}

 

Category Entity
import {
  BaseEntity,
  Column,
  Entity,
  PrimaryGeneratedColumn,
  CreateDateColumn,
  UpdateDateColumn,
  DeleteDateColumn,
} from 'typeorm';

@Entity({ name: 'category' })
export class Category extends BaseEntity {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  //length 설정하지 않으면 기본 255 길이 설정
  @Column({
    type: 'varchar',
    comment: '카테고리 이름',
  })
  name: string;

  @CreateDateColumn({ name: 'create_at', comment: '생성일' })
  createdAt: Date;

  @UpdateDateColumn({ name: 'update_at', comment: '수정일' })
  updatedAt: Date;

  @DeleteDateColumn({ name: 'delete_at', comment: '삭제일' })
  deletedAt?: Date | null;
}

N : M(다 대 다 ) 관계를 설정 할 때는 @ManyToMany 데코레이터를 사용합니다.

 

두 Entity를 선언하면 두 Entity를 연결해주는 Entity가 생성이 됩니다. (board_category_category)

 

board_category_category 테이블

 

게시글은 여러 카테고리에 소속 될 수 있기 때문에 Category 배열로 속성을 갖습니다.

 

 

board 테이블

 

category 테이블

 

위 Entity를 확인하면 FK(foreign key:외래키)를 board_category_category 테이블에게 위임한 걸 알 수 있습니다.

 

이번 시간에는 TypeORM에서 관계 설정에 대해 알아봤습니다.

 

궁금한 사항은 댓글을 남겨주시면 감사하겠습니다. :)

 

소스 저장소

github: https://github.com/Ryan-Sin/Node_Nest/tree/v6

 

GitHub - Ryan-Sin/Node_Nest

Contribute to Ryan-Sin/Node_Nest development by creating an account on GitHub.

github.com