[TypeScript] orm

Vorhandenheit ·2022년 5월 26일
0

JS/Node 

목록 보기
45/63
post-thumbnail

Typeorm

![](https://velog.velcdn.com/images/tastestar/post/93fcfa2f-5730-4afd-
9154-b101377269fd/image.png)

타입스크립트를 생성하고 typeorm을 생성하면 자동적으로 user라는게 뜨게됩니다. 어떻게 작동하는지 나타내는게 무엇인지 정리해볼려고합니다.

1. 패턴

Typeorm 패턴에는 2가지가 있습니다. 하나는 Active Record패턴이고 다른 하나는 Data Mapper패턴입니다.

(1) Active Record 패턴

Entitiy에 쿼리 메소드를 정의하고, 쿼리 메소드를 사용하여 객체를 저장, 제거, 불러옵니다.
BaseEntitiy를 사용하여 새로운 클래스에 상속하게 한 후 사용할 수 있습니다.

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

@Entity()
export class User extends BaseEntity {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  firstName: string;

  @Column()
  lastName: string;

  @Column()
  isActive: boolean;

  static findByName(firstName: string, lastName: string) {
    return this.createQueryBuilder('user')
      .where('user.firstName = :firstName', { firstName })
      .andWhere('user.lastName = :lastName', { lastName })
      .getMany();
  }
}

(2) Data Mapper 패턴

repository를 이용하여 객체를 저장, 제거, 불러옵니다. 데이터 모델과 액션을 분리하고 싶다면 Data Mapper패턴을 이용합니다.
규모가 큰 애플리케이션에 적합하고 유지 보수에 효과적입니다.
해당 패턴을 사용하기위해서는 스키마를 정의할 파일과 Repository로 상속된 별도의 객체가 필요합니다.

import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  firstName: string;

  @Column()
  lastName: string;

  @Column()
  isActive: boolean;
}

2. Entitiy

엔티티를 정의해줍니다. 엔티티는 데이터베이스에서 테이블을 의미하고 @Entitiy로 데코레이트된 모델을 말합니다.

typeorm은 이 데코레이터(@)를 이용하여 컬럼의 속성을 부여할 수 있습니다.

@Entity('users')
export class User {}

테이블 명을 따로 지정하지않아도 클래스명으로 매핑하지만, 옵션으로 테이블명을 지정할 수 있습니다.

@Entity({
  name: 'users',
  engine: 'MyISAM',
  database: 'example_dev',
  schema: 'schema_with_best_tables',
  synchronize: false,
  orderBy: {
    name: 'ASC',
    id: 'DESC',
  },
})
export class User {}
  • name : 테이블 이름
  • 선택된 DB 서버의 데이터베이스 이름
  • schema : 스키마 이름
  • engine : 테이블 생성 중에 설정할 수 있는 DB엔진 이름
  • synchronize : false로 설정할 시 스키마 싱크를 건너뜁니다.
  • orderBy : QueryBuilder와 find를 실행할 때 엔티티의 기본 순서를 지정합니다.

데코레이션

(1) Column

@Column({ tpye: 'varchar', length: 200, unique: true })
  • type : ColumnType
  • length : string | number :
  • onUpdate : string : cascading을 하기위한 옵션입니다.
  • nullable : boolean : 칼럼을 null이나 not Null로 만드는 옵션입니다. 기본값은 false입니다.
  • default : stirng : 칼럼에 Default값을 추가합니다.
  • unique : boolean : 유니크 constraint를 만듭니다. 기본값은 false입니다.
  • enum : string[] | AnyEnum : 칼럼의 값으로 enum을 사용할 수 있습니다.

(2) PrimaryGeneratedColumn

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number
}
  • increment : AUTO_INCREMENT를 사용해서 1씩 증가하는 ID를 부여합니다. 기본 옵션입니다.
  • uuid : 유니크한 uuid를 사용할 수 있습니다.

(3) CreateDateColumn

해당 열이 추가된 시각을 자동으로 기록합니다. 옵션을 적지않으면 datetime으로 기록됩니다.

@Entity()
export class User {
  @CreateDateColumn()
  createdAt: Date
}

(4) UpdateDateColumn

해당 열이 수정된 시각을 자동으로 기록합니다. 옵션을 적지않으면 datetime타입으로 기록됩니다.

@Entity()
export class User {
  @UpdateDateColumn()
  updatedAt: Date
}

Relaion

관계는 단방향과 양방향 모두 작성이 가능합니다.

(1) OneToOne

@Entity()
export class Profile {    
  @PrimaryGeneratedColumn()
  id: number
  
  @Column()
  gender: string
  
  @Column()
  photo: string

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

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number
    
  @Column()
  name: string

  @OneToOne(type => Profile, profile => profile.user)
  @JoinColumn()
  profile: Profile
}

JoinColumn을 사용한 필드는 FK로 타켓 테이블에 등록됩니다. 이는 반드시 한쪽 테이블에서만 사용해야합니다.

(2) ManyToOne/OneToMany

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number

  @Column()
  name: string

  @OneToMany(type => Photo, photo => photo.user)
  photos: Photo[]
}


@Entity()
export class Photo {
  @PrimaryGeneratedColumn()
  id: number

  @Column()
  url: string

  @ManyToOne(type => User, user => user.photos)
  user: User
}

JoinColumn을 생략할 수 있습니다.
OneToMany 는 ManyToOne이 없으면 안됩니다. 하지만 반대로 ManyToOne은 OneToMany이 없어도 정의 할수 있습니다. ManyToOne을 설정한 테이블에는 relation id가 외래키를 가지고 있게 됩니다.

(3) ManyToMany

@Entity()
export class Category {
  @PrimaryGeneratedColumn()
  id: number

  @Column()
  name: string
}

@Entity()
export class Question {
  @PrimaryGeneratedColumn()
  id: number

  @Column()
  title: string

  @Column()
  text: string

  @ManyToMany(() => Category)
  @JoinTable()
  categories: Category[]
}

ManyToMany관계에서는 JoinTable이 반드시 필요합니다. 한쪽 테이블에만 JoinTable을 넣어주면 됩니다.

JoinColumn/JoinTabel

옵션

  • eager : N+1 문제르 ㄹ제어할 수 있씁니다.
  • cascade,onDelete : 관계가 연결된 객체를 추가/수정/삭제되도록 할 수 있습니다.

JoinColumn

테이블에 자동으로 컬럼명과 참조 컬럼명을 합친 이름의 칼럼을 만들어냅니다

@Entity()
export class Post {
  @ManyToOne(type => Category)
  @JoinColumn({
    name: 'category_id',
    referencedColumnName: 'name'
  })
  category: Category
}

@Entity()
export class Category {
  @PrimaryGeneratedColumn()
  id: number

  @Column()
  name: string
}

JoinTable

M:N 관계에서 사용하며 연결테이블을 설정할 수 있습니다.

@Entity()
export class Question {
  @ManyToMany(type => Category)
  @JoinTable({
    name: 'question_categories',
    joinColumn: {
      name: 'question',
      referencedColumnName: 'id'
    },
    inverseJoinColumn: {
      name: 'category',
      referencedColumnName: 'id'
    }
  })
  categories: Category[]
}

@Entity()
export class Category {
  @PrimaryGeneratedColumn()
  id: number

  @Column()
  name: string
}

RelationId

1:N/M:N 관계에서 entitiy에 명시적으로 관계가 있는 테이블의 칼럼 id를 적고싶은 경우 사용합니다.

@Entity()
export class Post {
  @ManyToOne(type => Category)
  category: Category

  @RelationId((post: Post) => post.category)
  categoryId: number
}

// using many to many
@Entity()
export class Post {
  @ManyToMany(type => Category)
  categories: Category[]

  @RelationId((post: Post) => post.categories)
  categoryIds: number[]
}

Index/Unique/Check

테이블의 쿼리속도를 올려주는 자료구조입니다.

Index

테이블 전체에 인덱스를 걸고싶은 경우 Entitiy() 아래 Index()를 추가할 수도 있습니다.

@Entity()
export class User {
  @Index()
  @Column()
  firstName: string

  @Index({ unique: true })
  @Column()
  lastName: string
}

// using with entity
@Entity()
@Index(['firstName', 'lastName'], { unique: true })
export class User {
  @Column()
  firstName: string
  
  @Column()
  lastName: string
}

Unique

특정 칼럼에 고유키 제약조건을 생성할 수 있습니다. 테이블 자체에만 적용하는게 가능합니다.

@Entity()
@Unique(['firstName', 'lastName'])
export class User {
  @Column()
  firstName: string
  
  @Column()
  lastName: string
}

Check

테이블에서 데이터 추가 쿼리가 날아오면 값을 체크하는 역할을 합니다.

@Entity()
@Check('"age" > 18')
export class User {
  @Column()
  firstName: string
  
  @Column()
  firstName: string
  
  @Column()
  age: number
}
``

### Transaction
데이터베이스 내에서 하나의 그룹으로 처리해야하는 명령문을 모아서 처리하는 작업의 단위를 말합니다. 여러 개의 명령어의 집합이 정상적으로 처리되면 정상종료되며 하나의 명령어라도 잘못되면 전체 취소합니다.

데코레이터 `Transaction`,`TransactionManager`,`TransactionRepository`를 사용한 패턴입니다.
```javascript
// using transaction manager
@Transaction({ isolation: 'SERIALIZABLE' })
save(@TransactionManager() manager: EntityManager, user: User) {
    return manager.save(user)
}

// using transaction repository
@Transaction({ isolation: 'SERIALIZABLE' })
save(user: User, @TransactionRepository(User) userRepository: Repository<User>) {
    return userRepository.save(user) 
}

출처

https://overcome-the-limits.tistory.com/609?category=973842
https://seungtaek-overflow.tistory.com/15
https://intrepidgeeks.com/tutorial/typeorm-basic-usage
https://blog.naver.com/pjt3591oo/222309864102
https://yangeok.github.io/orm/2020/12/14/typeorm-decorators.html

profile
읽고 기록하고 고민하고 사용하고 개발하자!

0개의 댓글