Nest.js (5) TypeORM

Seong·2022년 11월 20일
0

Nest.js

목록 보기
5/9
post-thumbnail

ORM이란?
객체와 관계형 데이터베이스의 데이터를 자동으로 변형 및 연결하는 작업,
TypeORM은 node.js에서 실행되고 TypeScript로 작성된 객체 관계형 매퍼 라이브러리다.

TypeORM의 특징과 이점

  • 모델을 기반으로 데이터베이스 테이블 체계를 자동으로 생성

  • 데이터베이스에서 개체를 쉽게 삽입, 업데이트 및 삭제할 수 있음

  • 테이블 간의 매핑(일대일, 일대 다 및 다 대다)을 만듭니다.

  • 간단한 CLI 명령을 제공함

  • TypeORM은 간단한 코딩으로 ORM 프레임워크를 사용하기 쉬움

  • TypeORM은 다른 모듈과 쉽게 통합됨

설치

강의에서는 postgresql을 사용했지만.
나는 일단 점유율높은 MySQL사용할 예정이다.

1.일차적으로 TypeORM 설치

npm install typeorm

reflect-metadata랑 @types/node도 설치하라고 적혀있긴한데, Nest깔면 기본적으로 패키지에 있어서 패스한다.

2.Mysql과 연결할 수 있게 mysql2 설치

npm install mysql2

3.nest.js와 typeORM을 연동시키기

npm i @nestjs/typeorm

설정

아예 프로젝트를 새로만들면
npx typeorm init 으로 생성할수 있지만 이미 nest로 프로젝트를 만들어서 config파일을 직접 작성해야한다.
config/typeorm.config.ts 파일에 설정값을 만들어주자

import { TypeOrmModuleOptions } from "@nestjs/typeorm";


export const typeORMConfig:TypeOrmModuleOptions={
  type: "mysql",    //사용하는 DB, mysql , oracle등등
  host: "localhost",
  port: 3306,
  username: "root",
  password: "password",
  database: "nestcat",
  entities: [추후 추가],
  synchronize: true,   //동기화
}

그 후 Root Module에서 import 한다

@Module({
  imports: [
    BoardModule,
    ConfigModule.forRoot(),
    TypeOrmModule.forRoot(typeORMConfig),
  ],
  controllers: [],
  providers: [],
})

Entity

Sequelize의 migrate처럼 클래스로 테이블을 생성해준다

@Entity()
// @Unique(['유니크한 컬럼명'])  유니크값주기
export class BoardORM extends BaseEntity {
  @PrimaryGeneratedColumn() //기본 키 값
  id: number;
  @Column()
  title: string;
  @Column({nullable :true})   //null 가능
  description: string;
  @Column()
  status: BoardStatus;
  @CreateDateColumn() //createdAt
  createdAt: Date;
  @UpdateDateColumn() //updaatedAt
  updatedAt: Date;
  @Column({default:222})  //default value
  default: number
}

그후 config파일에 entity를 추가한다

  entities: [BoardORM],

서비스 적용

생성자로 Board Entity를 추가한다.

  constructor(
    @InjectRepository(BoardORM) boardRepository: Repository<BoardORM>,
  ) {}

그후 모듈에서도 Entity를 Import한다

@Module({
imports:[TypeOrmModule.forFeature([BoardORM])],
controllers: [BoardController],
providers: [BoardService],
})

전부 찾기

async getAllBoards(): Promise<BoardORM[]> {
 return this.boardRepository.find({order : {createdAt:"DESC"}})
}

생성일 기준으로 내림차순.

하나만 찾기

Service.ts
findOneBy 기본적으로 where가 적용되어있다

  async getBoardById(id: number): Promise<BoardORM> {
    const found = await this.boardRepository.findOneBy({id});

findOne

  const result = await this.userRepository.findOne({
    where: { id },
},

생성

Service.ts

  async createBoard(boardDto: BoardDto): Promise<BoardORM> {
    const { title, description } = boardDto;
    const board = this.boardRepository.create({
      title,
      description,
      status: BoardStatus.PUBLIC,
    });
    await this.boardRepository.save(board);
    return board;
  }

삭제

   const result = await this.boardRepository.delete(id);
   if(result.affected === 0){
     throw new NotFoundException(`Can't Find Board with id ${id}`)
   }

수정

async updateBoardStatus(id: number, status: BoardStatus): Promise<BoardORM> {
 const board = await this.getBoardById(id);
 board.status = status;
 await this.boardRepository.save(board);
 return board;
}

트랜잭션

constructor(
     private dataSource: DataSource,
) {}

const queryRunner = this.dataSource.createQueryRunner(); //트랜잭션을위한 쿼리 러너
await queryRunner.connect();
await queryRunner.startTransaction();

try {
  await queryRunner.manager.getRepository(Memotags).delete({ memoId });
  const memos = await queryRunner.manager
    .getRepository(Memo)
    .query(
      `UPDATE memo set title="${title}", content ="${content}" where id = ${memoId}`
    );
  if (tags) {
    await Promise.all(
      tags.map(async (element: string) => {
        let createdTag = await queryRunner.manager
          .getRepository(Tags)
          .findOne({
            where: { tagName: element },
          });
        if (!createdTag) {
          createdTag = await queryRunner.manager.getRepository(Tags).save({
            tagName: element,
          });
        }
        await queryRunner.manager.getRepository(Memotags).save({
          memoId,
          tagsId: createdTag.id,
        });
      })
    );
  }
  await queryRunner.commitTransaction();
  return memos;
} catch (error) {
  console.error("에러메시지:", error);
  await queryRunner.rollbackTransaction(); //실패 시 롤백
  return null;
} finally {
  queryRunner.release();
}

const queryRunner = connection.createQueryRunner();
await queryRunner.connect();
await queryRunner.startTransaction();

await queryRunner.manager.getRepository

다하고 queryRunner를 릴리즈하는것을 잊지말자.

관계 설정

일대다 관계

  @OneToMany(() => Comments, (comments) => comments.User)
  Comments: Comments[];

  @ManyToOne(() => Users, (users) => users.Comments, {
    onDelete: 'SET NULL',
    onUpdate: 'CASCADE',
  })
  @JoinColumn([{ name: 'UserId', referencedColumnName: 'id' }])
  User: Users;
 return this.boardRepository.find({ select:{
      user :{
        id:true,
        userName:true,
        password:false
      }
    },order: { createdAt: 'DESC' },relations:['user'] });

다대다 관계

  @ManyToMany(() => Tags, (tags) => tags.memotags)

  memotags: Tags[];
 @ManyToMany(() => Memo, (memo) => memo.memotags)
  @JoinTable({
    name: "memotags",
  })
  memotags: Tags[];
profile
메모장

0개의 댓글