ORM이란?
객체와 관계형 데이터베이스의 데이터를 자동으로 변형 및 연결하는 작업,
TypeORM은 node.js에서 실행되고 TypeScript로 작성된 객체 관계형 매퍼 라이브러리다.
모델을 기반으로 데이터베이스 테이블 체계를 자동으로 생성
데이터베이스에서 개체를 쉽게 삽입, 업데이트 및 삭제할 수 있음
테이블 간의 매핑(일대일, 일대 다 및 다 대다)을 만듭니다.
간단한 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: [],
})
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[];