특정 엔터티 이벤트를 리슨할 수 있음.
근데 데이터베이스에서 리스너를 호출하면 안 됨. 대신 구독자를 사용하기.
엔터티 리스너는 엔터티 자체에 정의되며, 해당 엔터티의 생명주기 이벤트(예: 저장, 로드, 업데이트, 삭제 등)에 반응합니다. 이 리스너들은 각 엔터티 클래스 내에 메소드로 정의되고, 특정 이벤트가 발생할 때 자동으로 호출됩니다.
import { Entity, PrimaryGeneratedColumn, Column, BeforeInsert, getRepository } from "typeorm";
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
email: string;
@Column()
username: string;
@BeforeInsert()
async checkUsername() {
// User 엔터티의 레포지토리를 가져옵니다.
// 이런 식으로 리스너 안에서 디비 호출하지 말라는 말
const userRepository = getRepository(User);
// 같은 username을 가진 사용자가 이미 있는지 확인합니다.
const userExists = await userRepository.findOne({
where: { username: this.username }
});
if (userExists) {
throw new Error("Username already exists!");
}
}
}
이는 리스너 내에서 추가적인 데이터베이스 I/O를 발생시킵니다. 이는 성능 저하를 초래하고, 트랜잭션의 복잡성을 증가시킬 수 있습니다. 또한, 이러한 방식은 리스너의 본래 목적인 간단한 데이터 검증 및 조건 확인을 넘어서는 로직을 포함하고 있어 권장되지 않습니다.
@Entity()
export class Post {
@AfterLoad()
updateCounters() {
if (this.likesCount === undefined) this.likesCount = 0
}
}
@Entity()
export class Post {
@BeforeInsert()
updateDates() {
this.createdDate = new Date()
}
}
@Entity()
export class Post {
@AfterInsert()
resetCounters() {
this.counters = 0
}
}
@Entity()
export class Post {
@BeforeUpdate()
updateDates() {
this.updatedDate = new Date()
}
}
@Entity()
export class Post {
@AfterUpdate()
updateCounters() {
this.counter = 0
}
}
@Entity()
export class Post {
@BeforeRemove()
updateStatus() {
this.status = "removed"
}
}
@Entity()
export class Post {
@AfterRemove()
updateStatus() {
this.status = "removed"
}
}
@EventSubscriber()
export class PostSubscriber implements EntitySubscriberInterface<Post> {
listenTo() {
return Post
}
beforeInsert(event: InsertEvent<Post>) {
console.log(`BEFORE POST INSERTED: `, event.entity)
}
}
특정 엔터티가 아니라 범용적으로 이벤트를 구독하려면 EntitySubscriberInterface에서 제네릭을 빼면 됨
@EventSubscriber()
export class PostSubscriber implements EntitySubscriberInterface {
/**
* Called after entity is loaded.
*/
afterLoad(entity: any) {
console.log(`AFTER ENTITY LOADED: `, entity)
}
}


구독자를 사용해서 엔터티 이벤트트를 처리할 때, 각 이벤트 처리 메소드에 이벤트 객체가 전달됨.
이벤트 객체는 다음 객체(인스턴스)가 포함됨.
전역 인스턴스가 아니라 이렇게 전달된 인스턴스를 사용해야 한다!