Web

공연 예매 프로젝트 - TroubleShooting : 검색 기능, 연간 관계

noeul_noeul__ 2024. 7. 8. 22:51

오늘은 

공연 예매 프로젝트를 진행하며 발생한 트러블 슈팅 내용을 첨부합니다. 

1. 검색 기능 구현 중 Join된 데이터를 바탕으로 검색하려면 ?

더보기

1. 개요

공연 테이블을 구현했습니다.

구현될 기능으로 검색 기능 중 카테고리 기반으로 검색을 추가하고자 하였습니다.

그 과정에서 문법적인 에러가 발생하였고 해결한 방법을 다뤄보겠습니다.

2. Trouble Shooting

2.1 배경

이번 프로젝트에서 ERD입니다. category 테이블과 shows 테이블은 1:N 관계로서, shows 테이블이 category 테이블로 그룹화 되고 있습니다.

공연 검색 API의 명세서입니다.

검색 기준은 Query Param을 사용하여 전달받고,

  1. 전체 목록 검색
  2. 제목 기반 검색
  3. 카테고리 기반 검색
  4. 제목 + 카테고리 기반 검색

4가지 조건으로 공연 정보를 검색할 수 있습니다.

2.2 발단

명세서의 URL은 shows로 공연 테이블을 참조합니다. 카테고리 기반 검색을 한다면 따로 API를 만들어 /category 라는 URL을 통해 카테고리 테이블을 먼저 참조해서 그룹화 된 공연 정보를 꺼내올 수 있을겁니다.

하지만 검색 API를 조건 추가를 위해 한번 더 나누는 것은 효율적이지 못하다는 판단이 들었고, relation을 통해 shows 테이블에서 category를 타고 데이터를 꺼내오는 방법을 선택했습니다.

2.3 전개

shows.service.ts

 

처음 코드를 작성하고 마주한 에러입니다. CATEGORY는 enum으로 작성되었기 때문에 타입을 지정해준건데 왜 에러가 나는지 고민했습니다.

2.4. 위기

타입을 Category entity로 변경했습니다. 타입 에러는 해결되었지만 Insomnia 테스트 시 Server 에러가 발생하기 시작했습니다.

2.5 절정

타입은 다시 enum으로 변경했고, 동기 분의 조언을 받아 where 조건을 카테고리 안에 카테고리를 검색하도록 변경했습니다.

해당 category 엔티티입니다. 테이블 명도 category, 컬럼명도 category이기 때문에 구분이 어렵습니다. 구현한 코드 상으로는 아래와 같이 조건이 들어가고 있습니다.

category: { category : category } // 카테고리 안에 카테고리 중 입력받은 카테고리

2.6 결말

relations를 사용했을 때 관계된 테이블에 깊이를 고려하지 않고 검색 조건을 넣어 발생한 문제였습니다. 그리고 구분하기 쉬운 명칭을 사용하지 않아 해결이 어려웠고 시간이 많이 소모되었습니다. 한번 더 변수명 생성의 중요성과 조건 검색 시 관계를 주는 법에 대해서 공부하게 되었습니다.

3. 마무리

  1. 검색 조건 설정 시 TypeError 발생
  2. 사실 TypeError가 아닌 조건 검색 깊이 설정 문제였다.
  3. 명시적이고 구분하기 쉬운 변수 명을 사용하자.

2. 테이블 간 연간 관계, cascade 설정 

더보기

1. 개요

사용자가 티켓을 구매하게 되면 네 가지 데이터가 함께 생성, 업데이트 됩니다.

판매된 좌석 정보 → 티켓 정보 → 금액에 대한 로그 → 사용자의 가용 금액 차감

반대로 티켓 예매를 취소하게 되면 생성된 데이터 삭제, 가용 금액 충전이 다시 한번에 이뤄져야 합니다.

티켓 예매를 구현하기 위해 코드를 작성하던 중 마주한 문제를 다뤄보겠습니다.

2. Trouble Shooting

2.1 배경

 

 

프로젝트 ERD입니다.

tickets - purchaseHistories - salesSeats는 tickets를 중심으로 OneToOne 관계를 이루고 있습니다.

공연 예매가 취소된다면, tickets, purchaseHistories, salesSeats가 전부 삭제되어야 합니다.

2.2 발단

여러 번의 delete 메서드를 통해 한 테이블 씩 특정하여 트랜잭션으로 묶은 뒤 삭제할 수도 있지만, CASCADE 속성을 사용하여 티켓 데이터가 삭제된다면 연관된 salesSeats, purchaseHistories가 함께 삭제되도록 구현하고자 하였습니다.

2.3 전개

각각의 엔티티에 CASCADE 속성을 추가했습니다. 여기서 salseSeat에는 ticket_id를 저장해주지 않았는데 (@JoinColumn 속성을 추가하지 않았습니다. ) 이는 tickets와 salesSeats에서 연간 관계를 설정해주었기 때문에 따로 컬럼이 필요하다고 생각하지 않았기 때문입니다.

2.4. 위기

ticket을 삭제했을 때 purchaseHistories는 삭제되었지만 salesSeat는 삭제되지 않았습니다.

2.5 절정

saleSeats에 ticket_id를 추가하였습니다.

FOREIGN KEY를 설정한 것입니다. 이로써 salesSeats와 tickets는 OneToOne 관계이지만 salesSeats가 tickets를 참조하도록 설정이 되었습니다.

2.6 결말

OneToMany에서의 FK 설정 뿐만 아니라 OneToOne에서의 FK 설정 또한 중요하다는 것을 배웠습니다. 연간 관계 형성 이후에 FK 설정을 명시적으로 해야 데이터끼리 관계를 이룰 수 있음을 알았고 이후 CASCADE 속성이 정상 작동하였습니다.

3. 마무리

  1. 티켓 예매 취소 기능을 구현하기 위해 연간 관계를 이루는 데이터들을 한 번에 삭제하는 코드를 작성했다.
  2. CASCADE 속성으로 구현하던 중 삭제가 되는 테이블과 삭제가 되지 않는 테이블이 존재하였다.
  3. FK의 부재로 인한 문제였다.