문제점
이번 글에서는 JPA를 사용하면서 겪었던
Entity mapping 이슈 관련된 내용을 정리해볼까 합니다.
저는 회사에서 결제 시스템을 담당하고 있는데,
저희 결제 시스템의 DB Schema는 대략적으로 다음과 같습니다.
(설명을 위해 간소화시켰으며 실제 schema와는 차이가 있습니다.)
간략하게 설명을 드리면,
하나의 결제건(purchase)에는 여러 상품이 포함될 수 있으며
결제된 상품(product)에는 상품의 id와 결제의 id(order_id)의 조합을 primary key로 사용하고 있습니다.
그리고 각각의 Entity는 다음과 같이 정의되어 있습니다.
Purchase.java
@Data
@Entity
public class Purchase {
@Id
private BigInteger id;
@OneToMany
@JoinColumn(name = "order_id")
private List<Product> products;
@Column
private LocalDateTime orderedDateTime;
}
Product.java
@Data
@Entity
public class Product {
@Id
private BigInteger id;
@Column
private String name;
@Column
private Double amount;
@Column
private String currencyCode;
}
Purcase Entity는 1 : N 단방향 매핑으로 Product와 매핑되도록 정의가 되어있습니다.
마지막으로 테스트를 위해 세팅한 데이터는 아래와 같습니다.
두 개의 결제건(id는 2, 3)에는 각각 국내와 해외에서 상품을 구매하였다고 가정하였습니다.
위 두 상품은 실제로는 어디서 결제했냐만 다를뿐 동일한 상품이기 때문에
동일한 상품 id를 가지고 있습니다.
product table에서는 id와 order_id의 조합이 유니크하기 때문에 데이터상으로도 문제는 없습니다.
그럼 이제 주문 내역을 조회하는 API를 통해 위 데이터를 조회해 보겠습니다.
기대한 결과와는 다르게 두 결제건(id 2, 3) 모두
국내에서 결제한 상품이 조회되었습니다.
원인
결론부터 말씀드리면, 문제는 Product Entity에 있었습니다.
Product.java
@Data
@Entity
public class Product {
@Id
private BigInteger id;
@Column
private String name;
@Column
private Double amount;
@Column
private String currencyCode;
}
이전에 살펴봤던 Schema를 다시 보면,
primary key로 id와 order_id를 사용하고 있지만
Product entity에서는 id만을 entity를 식별하는 값으로 활용하고 있습니다.
이를 해결하기 위해서는 order_id 역시 식별값으로 포함을 시켜야합니다.
알고보면 당연한 내용이지만,
product의 id가 동일하지 않았다면 문제없이 결제 내역 조회가 가능하기 때문에
원인을 찾기까지 생각보다 많은 시간을 소비했습니다.
(이 글을 보시는 분들은 저처럼 불필요한 시간 낭비를 하시지 않았으면 좋겠습니다.)
해결책
위에서 설명했던 것처럼 이를 해결하기 위해서는
order_id를 product entity의 식별값으로 포함시켜야 합니다.
Product.java
@Data
@Entity
public class Product implements Serializable {
@Id
private BigInteger id;
@Id
@ManyToOne
@JoinColumn(name = "order_id")
@JsonBackReference
private Purchase purchase;
@Column
private String name;
@Column
private Double amount;
@Column
private String currencyCode;
}
그럼 여기까지 entity mapping 이슈를 겪고 이를 해결한 경험을 정리해보았습니다.
감사합니다.