전 문서에서는 DB 연결을 하는 것까지 작성하였고
이어서 구성된 ERD 를 참고하여 Entities 작성 및 dto를 작성해 볼 예정이다.
일단 기본적으로 데코레이터를 작성하지 않고 기본적인 틀부터 작성을 해보겠다.
Entity 순서 : 1. user, 2. show, 3. schedule, 4. seat, 5. book
1.
import { UserRole } from '../roles/user-role';
import { Book } from 'src/book/entities/book.entity';
export class User {
id: number;
email: string;
password: string;
nickname: string;
points: number;
role: UserRole;
createdAt: Date;
updatedAt: Date;
books: Book[];
}
export enum UserRole {
Customer = 'Customer',
Admin = 'Admin',
}
2.
import { CategoryRole } from '../roles/category-role';
import { Schedule } from './schedule.entity';
export class Show {
id: number;
title: string;
description: string;
category: CategoryRole;
place: string;
price: number;
thumbnail: string;
createdAt: Date;
updatedAt: Date;
schedules: Schedule[];
}
export enum CategoryRole {
Concert = 'Concert',
Musical = 'Musical',
Play = 'Play',
Sports = 'Sports',
Event = 'Event',
}
3.
import { Show } from './show.entity';
import { Seat } from './seat.entity';
export class Schedule {
id: number;
showId: number;
date: Date;
time: string;
createdAt: Date;
updatedat: Date;
show: Show;
seat: Seat;
}
자칫 여기서 ERD 구성에 따라 1(schedule):N(books) 연결로 인해 books: Book[]; 가 필요하다 생각 할 수 있지만
Schedule 은 예약정보를 가져올 필요가 없기 때문에 books: Book[]; 를 굳이 연결해줄 필요는 없다.
4.
import { Schedule } from './schedule.entity';
export class Seat {
id: number;
scheduleId: number;
availableSeats: number;
totalSeats: number;
createdAt: Date;
updatedAt: Date;
schedule: Schedule;
}
5.
import { Schedule } from 'src/show/entities/schedule.entity';
export class Book {
id: number;
userId: number;
scheduleId: number;
createdAt: Date;
updatedAt: Date;
user: User;
schedule: Schedule;
}
데코레이터를 곁들인 Entities
1.
import {
Column,
CreateDateColumn,
Entity,
OneToMany,
PrimaryGeneratedColumn,
UpdateDateColumn,
} from 'typeorm';
import { UserRole } from '../roles/user-role';
import { Book } from 'src/book/entities/book.entity';
import { getPoints } from '../points/points';
@Entity({
name: 'users',
})
export class User {
@PrimaryGeneratedColumn({ unsigned: true })
id: number;
@Column({ unique: true })
email: string;
@Column()
password: string;
@Column()
nickname: string;
@Column({ unsigned: true, default: getPoints.DEFAULT.POINTS })
points: number;
@Column({ type: 'enum', enum: UserRole, default: 'Customer' })
role: UserRole;
@CreateDateColumn()
createdAt: Date;
@UpdateDateColumn()
updatedAt: Date;
@OneToMany((type) => Book, (book) => book.user)
books: Book[];
}
export const getPoints = {
DEFAULT: {
POINTS: 1000000,
},
MAXIMUM: {
POINTS: 50000,
},
};
2.
import {
Column,
CreateDateColumn,
Entity,
OneToMany,
PrimaryGeneratedColumn,
UpdateDateColumn,
} from 'typeorm';
import { CategoryRole } from '../roles/category-role';
import { Schedule } from './schedule.entity';
@Entity({
name: 'shows',
})
export class Show {
@PrimaryGeneratedColumn({ unsigned: true })
id: number;
@Column({ unique: true })
title: string;
@Column()
description: string;
@Column({ type: 'enum', enum: CategoryRole })
category: CategoryRole;
@Column()
place: string;
@Column()
price: number;
@Column({ nullable: true })
thumbnail: string;
@CreateDateColumn()
createdAt: Date;
@UpdateDateColumn()
updatedAt: Date;
@OneToMany((type) => Schedule, (schedule) => schedule.show)
schedules: Schedule[];
}
3.
import {
Column,
CreateDateColumn,
Entity,
ManyToOne,
OneToMany,
OneToOne,
PrimaryGeneratedColumn,
UpdateDateColumn,
} from 'typeorm';
import { Show } from './show.entity';
import { Seat } from './seat.entity';
import { Book } from 'src/book/entities/book.entity';
@Entity({
name: 'schedules',
})
export class Schedule {
@PrimaryGeneratedColumn({ unsigned: true })
id: number;
@Column({ unsigned: true })
showId: number;
@Column()
date: Date;
@Column({ type: 'time' })
time: string;
@CreateDateColumn()
createdAt: Date;
@UpdateDateColumn()
updatedat: Date;
@ManyToOne((type) => Show, (show) => show.schedules, { onDelete: 'CASCADE' })
show: Show;
@OneToOne((type) => Seat, (seat) => seat.schedule, { cascade: true })
seat: Seat;
}
4.
import {
Column,
CreateDateColumn,
Entity,
JoinColumn,
OneToOne,
PrimaryGeneratedColumn,
UpdateDateColumn,
} from 'typeorm';
import { Schedule } from './schedule.entity';
import { seatCounts } from '../counts/seat-count';
@Entity({
name: 'seats',
})
export class Seat {
@PrimaryGeneratedColumn({ unsigned: true })
id: number;
@Column({ unsigned: true })
scheduleId: number;
@Column({ unsigned: true, default: seatCounts.DEFAULT.TOTAL_SEAT_COUNTS })
availableSeats: number;
@Column({ unsigned: true, default: seatCounts.DEFAULT.TOTAL_SEAT_COUNTS })
totalSeats: number;
@CreateDateColumn()
createdAt: Date;
@UpdateDateColumn()
updatedAt: Date;
@OneToOne((type) => Schedule, { onDelete: 'CASCADE' })
@JoinColumn()
schedule: Schedule;
}
export const seatCounts = {
DEFAULT: {
TOTAL_SEAT_COUNTS: 100,
},
};
5.
import { Schedule } from 'src/show/entities/schedule.entity';
import { User } from 'src/user/entities/user.entity';
import {
Column,
CreateDateColumn,
Entity,
ManyToOne,
PrimaryGeneratedColumn,
UpdateDateColumn,
} from 'typeorm';
@Entity({
name: 'books',
})
export class Book {
@PrimaryGeneratedColumn({ unsigned: true })
id: number;
@Column({ unsigned: true })
userId: number;
@Column({ unsigned: true })
scheduleId: number;
@CreateDateColumn()
createdAt: Date;
@UpdateDateColumn()
updatedAt: Date;
@ManyToOne((type) => User, (user) => user.books, { onDelete: 'CASCADE' })
user: User;
@ManyToOne((type) => Schedule, { onDelete: 'CASCADE' })
schedule: Schedule;
}
[Nest] 70864 - 2024. 08. 23. 오후 4:37:17 ERROR [TypeOrmModule] Unable to connect to the database. Retrying (2)...
QueryFailedError: Referencing column 'showId' and referenced column 'id' in foreign key constraint 'FK_fd750e49050f4ee65a4bffb25f1' are incompatible.
at Query.onResult (C:\Users\windo\nestjs-mindo\node_modules\typeorm\driver\src\driver\mysql\MysqlQueryRunner.ts:246:33)
at Query.execute (C:\Users\windo\nestjs-mindo\node_modules\mysql2\lib\commands\command.js:36:14)
at PoolConnection.handlePacket (C:\Users\windo\nestjs-mindo\node_modules\mysql2\lib\connection.js:481:34)
at PacketParser.onPacket (C:\Users\windo\nestjs-mindo\node_modules\mysql2\lib\connection.js:97:12)
at PacketParser.executeStart (C:\Users\windo\nestjs-mindo\node_modules\mysql2\lib\packet_parser.js:75:16)
at Socket.<anonymous> (C:\Users\windo\nestjs-mindo\node_modules\mysql2\lib\connection.js:104:25)
at Socket.emit (node:events:518:28)
at addChunk (node:internal/streams/readable:559:12)
at readableAddChunkPushByteMode (node:internal/streams/readable:510:3)
at Readable.push (node:internal/streams/readable:390:5)
오류 발생
에러 메시지를 보면 showId와 id라는 컬럼이 외래 키 제약 조건에서 서로 호환되지 않는다는 내용인것 같다.
windo@DESKTOP-6SMB85M MINGW64 ~/nestjs-mindo (main)
$ npm i --save typeorm-naming-strategies
added 1 package, and audited 749 packages in 2s
114 packages are looking for funding
run `npm fund` for details
37 moderate severity vulnerabilities
To address issues that do not require attention, run:
npm audit fix
To address all issues (including breaking changes), run:
npm audit fix --force
Run `npm audit` for details.
기억을 되살려서 Entity 참조테이블 데코레이터에 JoinColumn 을 사용하지 않기 위해 기억을 더듬어
패키지를 설치 하였다.
import { ConfigModule, ConfigService } from '@nestjs/config';
import { Book } from 'src/book/entities/book.entity';
import { Schedule } from 'src/show/entities/schedule.entity';
import { Seat } from 'src/show/entities/seat.entity';
import { Show } from 'src/show/entities/show.entity';
import { User } from 'src/user/entities/user.entity';
import { SnakeNamingStrategy } from 'typeorm-naming-strategies';
export const typeOrmConfig = {
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (configService: ConfigService) => ({
type: configService.get('DB_TYPE'),
host: configService.get('DB_HOST'),
port: configService.get('DB_PORT'),
username: configService.get('DB_USERNAME'),
password: configService.get('DB_PASSWORD'),
database: configService.get('DB_NAME'),
// entities: [User, Show, Schedule, Seat, Book],
autoLoadEntities: true,
synchronize: configService.get('DB_SYNC'),
namingStrategy: new SnakeNamingStrategy(),
}),
};
그리고 namingStrategy 를 사용하여 위와같이 작성을 해주었다.
그러나 오류는 계속 같은 문구로 발생 하였다.
그냥 직접적으로 연결해주었다.
@ManyToOne((type) => Show, (show) => show.schedules, { onDelete: 'CASCADE' })
@JoinColumn({ name: 'showId' })
show: Show;
[Nest] 86984 - 2024. 08. 23. 오후 5:16:13 LOG [NestFactory] Starting Nest application...
[Nest] 86984 - 2024. 08. 23. 오후 5:16:13 LOG [InstanceLoader] TypeOrmModule dependencies initialized +9ms
[Nest] 86984 - 2024. 08. 23. 오후 5:16:13 LOG [InstanceLoader] ConfigHostModule dependencies initialized +1ms
[Nest] 86984 - 2024. 08. 23. 오후 5:16:13 LOG [InstanceLoader] AppModule dependencies initialized +0ms
[Nest] 86984 - 2024. 08. 23. 오후 5:16:13 LOG [InstanceLoader] UserModule dependencies initialized +0ms
[Nest] 86984 - 2024. 08. 23. 오후 5:16:13 LOG [InstanceLoader] ShowModule dependencies initialized +0ms
[Nest] 86984 - 2024. 08. 23. 오후 5:16:13 LOG [InstanceLoader] BookModule dependencies initialized +0ms
[Nest] 86984 - 2024. 08. 23. 오후 5:16:13 LOG [InstanceLoader] AuthModule dependencies initialized +0ms
[Nest] 86984 - 2024. 08. 23. 오후 5:16:13 LOG [InstanceLoader] ConfigModule dependencies initialized +0ms
[Nest] 86984 - 2024. 08. 23. 오후 5:16:13 LOG [InstanceLoader] ConfigModule dependencies initialized +0ms
[Nest] 86984 - 2024. 08. 23. 오후 5:16:14 LOG [InstanceLoader] TypeOrmCoreModule dependencies initialized +565ms
[Nest] 86984 - 2024. 08. 23. 오후 5:16:14 LOG [InstanceLoader] TypeOrmModule dependencies initialized +0ms
[Nest] 86984 - 2024. 08. 23. 오후 5:16:14 LOG [InstanceLoader] TypeOrmModule dependencies initialized +0ms
[Nest] 86984 - 2024. 08. 23. 오후 5:16:14 LOG [InstanceLoader] TypeOrmModule dependencies initialized +0ms
[Nest] 86984 - 2024. 08. 23. 오후 5:16:14 LOG [RoutesResolver] AppController {/}: +4ms
[Nest] 86984 - 2024. 08. 23. 오후 5:16:14 LOG [RouterExplorer] Mapped {/, GET} route +1ms
[Nest] 86984 - 2024. 08. 23. 오후 5:16:14 LOG [RoutesResolver] UserController {/user}: +0ms
[Nest] 86984 - 2024. 08. 23. 오후 5:16:14 LOG [RouterExplorer] Mapped {/user, POST} route +1ms
[Nest] 86984 - 2024. 08. 23. 오후 5:16:14 LOG [RouterExplorer] Mapped {/user, GET} route +0ms
[Nest] 86984 - 2024. 08. 23. 오후 5:16:14 LOG [RouterExplorer] Mapped {/user/:id, GET} route +0ms
[Nest] 86984 - 2024. 08. 23. 오후 5:16:14 LOG [RouterExplorer] Mapped {/user/:id, PATCH} route +0ms
[Nest] 86984 - 2024. 08. 23. 오후 5:16:14 LOG [RouterExplorer] Mapped {/user/:id, DELETE} route +0ms
[Nest] 86984 - 2024. 08. 23. 오후 5:16:14 LOG [RoutesResolver] ShowController {/show}: +1ms
[Nest] 86984 - 2024. 08. 23. 오후 5:16:14 LOG [RouterExplorer] Mapped {/show, POST} route +0ms
[Nest] 86984 - 2024. 08. 23. 오후 5:16:14 LOG [RouterExplorer] Mapped {/show, GET} route +0ms
[Nest] 86984 - 2024. 08. 23. 오후 5:16:14 LOG [RouterExplorer] Mapped {/show/:id, GET} route +0ms
[Nest] 86984 - 2024. 08. 23. 오후 5:16:14 LOG [RouterExplorer] Mapped {/show/:id, PATCH} route +0ms
[Nest] 86984 - 2024. 08. 23. 오후 5:16:14 LOG [RouterExplorer] Mapped {/show/:id, DELETE} route +0ms
[Nest] 86984 - 2024. 08. 23. 오후 5:16:14 LOG [RoutesResolver] BookController {/book}: +0ms
[Nest] 86984 - 2024. 08. 23. 오후 5:16:14 LOG [RouterExplorer] Mapped {/book, POST} route +1ms
[Nest] 86984 - 2024. 08. 23. 오후 5:16:14 LOG [RouterExplorer] Mapped {/book, GET} route +0ms
[Nest] 86984 - 2024. 08. 23. 오후 5:16:14 LOG [RouterExplorer] Mapped {/book/:id, GET} route +0ms
[Nest] 86984 - 2024. 08. 23. 오후 5:16:14 LOG [RouterExplorer] Mapped {/book/:id, PATCH} route +0ms
[Nest] 86984 - 2024. 08. 23. 오후 5:16:14 LOG [RouterExplorer] Mapped {/book/:id, DELETE} route +0ms
[Nest] 86984 - 2024. 08. 23. 오후 5:16:14 LOG [RoutesResolver] AuthController {/auth}: +0ms
[Nest] 86984 - 2024. 08. 23. 오후 5:16:14 LOG [RouterExplorer] Mapped {/auth, POST} route +0ms
[Nest] 86984 - 2024. 08. 23. 오후 5:16:14 LOG [RouterExplorer] Mapped {/auth, GET} route +0ms
[Nest] 86984 - 2024. 08. 23. 오후 5:16:14 LOG [RouterExplorer] Mapped {/auth/:id, GET} route +0ms
[Nest] 86984 - 2024. 08. 23. 오후 5:16:14 LOG [RouterExplorer] Mapped {/auth/:id, PATCH} route +0ms
[Nest] 86984 - 2024. 08. 23. 오후 5:16:14 LOG [RouterExplorer] Mapped {/auth/:id, DELETE} route +0ms
[Nest] 86984 - 2024. 08. 23. 오후 5:16:14 LOG [NestApplication] Nest application successfully started +2ms
정상작동... 어디서부터 틀어진 것인지 모르겠다. 다시한번 살펴보아야겠다.
'TIL' 카테고리의 다른 글
Nest.js, TypeScript 프로젝트 mindo - 3 Hot( Auth ) (0) | 2024.08.23 |
---|---|
Nest.js, TypeScript 프로젝트 mindo - 1 Hot( configModule or Service ) (0) | 2024.08.21 |
Nest.js 강의 (1) ( ) (0) | 2024.08.02 |
TypeScript 강의 (12) ( 실습 : 도서관 프로그램 ) (0) | 2024.07.31 |
TypeScript 강의 (11) ( S.O.L.I.D ) (0) | 2024.07.30 |