현재 NestJS로 진행하고 있는 토이프로젝트에서
태그
기능을 추가하기 위해
Post 테이블과 Tag 테이블을 Join
한 post_tag
테이블을 만들었다.
TypeORM에서는 ManyToMany
로 관계를 정의 했을 때
조인테이블이 자동으로 생성된다
post_tag
<<< 임의로 이름을 명시하지 않는 경우 조인 되는 테이블이름이 섞여 생성된다.post
+_
+tag
joinTable({
name: "post_tag" <<<이렇게 자동생성되는 조인테이블 이름을 임의로 명시 할 수 있다.
})
조인테이블을 이용한 Post
에 태그를 추가하는것 까지는 쉽게 진행 되었는데
게시글을 수정을 할 때 게시글에 연결되어있는 태그
를 삭제해야 했는데
tag_id
를 이용해
조인테이블의 row만 삭제하고
post
테이블의 tags
속성만 삭제(테이블 row 전체 삭제x)
tag
테이블의 posts
속성만 삭제(마찬가지로 테이블 row 전체 삭제 x)
다음과 같이 결과가 나와야했다.
내가 구글링을 잘 못해인지..TypeORM 문서를 봐도 잘 설명이 안돼어있어 헤멨는데 겨우겨우 찾았다.
tag.service.ts
의 deleteTag
메서드
async deleteTag(
postId: string,
tagId: string,
): Promise<void> {
await getConnection()
.createQueryBuilder()
.delete()
.from('post_tag')
.where('postId = :postId AND tagId = :tagId', {
postId: postId,
tagId: tagId,
})
.execute();
}
TypeORM의 QueryBuilder
를 이용하여 자동생성된 joinTable post_tag
에 접근이 가능했다.
다대다 관계를 정의함에 있어서
TypeORM 에서는 두 가지 방법이 있다.
다대다
관계를 통해 자동생성된 조인테이블에 접근하여 삭제를 했는데두 번째
방법을 통해 진행 할 수도 있다.두 번째
방법은 모든 테이블을 직접 명시해주는 것인데
post
post_tag
tag
엔티티 파일을 직접 만들어 주는 것이다.
Post
엔티티@Entity()
export class Post{
@OneToMany(() => Post_tag, (tags) => tags.post)
tags: Post_tag[];
}
Tag
엔티티@Entity()
export class Tag{
@OneToMany(() => Post_tag, (posts) => posts.tag )
posts: Post_tag[];
}
Post_tag
엔티티@Entity()
export class Post_tag {
@Column("uuid")
post_id!: string;
@Column("uuid")
tag_id!: string;
@ManyToOne(()=>Post, (post) => post.tags)
post!: Post;
@ManyToOne( () => Tag, (tag) => tag.posts)
tag!: Tag;
}
위 와 같은 커스텀 엔티티 구성을 통해 직접 Post_tag
엔티티를 삭제 할 수있다.
const post_tag = await this.postTagRepository.softRemove({
post_id: postId, tag_id: tagId
})
delete
는 특정 속성 값으로 엔티티 전체를 삭제
remove
엔티티를 값으로 특정 엔티티 삭제
softRemove
와softDelete
는 엔티티의cascade
가true
일 경우부모
가 삭제되면자식
도 삭제 시켜준다.즉,
cascade
를true
하면post_tag
row를 삭제 할 때
post
와tag
엔티티 들도 삭제 될 수 있으니false
로 명시해야한다.
뭔가 간단해 보이는 기능인데,, 구현에 하루가 다 지나갔다..
TypeORM
의 기능을 쓰는 것도 중요하지만
sql 쿼리를 먼저 이해하고 기능이 있으면 덧 붙여 쓰는게 우선인게 느껴졌다.