내가 맡은 부분은 상품 부분이다.
Method: POST
Path: /products
Example Endpoint: https://localhost:8080/products
Request Parameters:
adminToken (String) : 관리자 토큰productName (String) : 상품 이름price (int) : 상품 가격description (String) : 상품 설명category (Category) : 카테고리productCondition (Condition) : 상품 상태productCount (int) : 상품 개수options (List<optionGroup): 상품 옵션optionGroupName (String) : 옵션 그룹명 (예: "색상", "사이즈")optionValues (List<OptionValue): 옵션 값 목록value (String): 옵션 값stock (int) : 재고createdAt (LocalDateTime) : 등록 시간{
"productName": "신발",
"price": 50000,
"description": "편안한 신발입니다.",
"category": SHOSE,
"productCondition": "NEW",
"options": [
{
"optionGroupName": "색상",
"optionValues": [
{ "value": "빨강", "stock": 5 },
{ "value": "검정", "stock": 10 }
] },
{
"optionGroupName": "사이즈",
"optionValues": [
{ "value": "230", "stock": 3 },
{ "value": "240", "stock": 7 },
{ "value": "250", "stock": 5 }
]
}
]
}Response: (ProductCreateResponse)
productId(Long) :상품 IDproductName (String) : 상품 이름price (int) : 상품 가격description (String) : 상품 설명category (Category) : 카테고리productCondition (Condition) : 상품 상태productCount (int) : 상품 개수options (List<optionGroup): 상품 옵션 그룹 목록optionGroupName (String) : 옵션 그룹명 (예: "색상", "사이즈")optionValues (List<OptionValue): 옵션 값 목록value (String): 옵션 값stock (int) : 재고createAt (LocalDateTime) : 등록 시간PUT/products/{productId}adminToken (String) : 관리자 토큰productId (Long) : 상품 IDproductName (String) : 상품 이름price (int) : 상품 가격description (String) : 상품 설명category (Category) : 카테고리productCondition (Condition) : 상품 상태options (List<optionGroup): 상품 옵션 그룹 목록optionGroupName (String) : 옵션 그룹명 (예: "색상", "사이즈")optionValues (List<String): 옵션 값 목록 (예: ["빨강", "파랑", "녹색"])value (String): 옵션 값stock (int) : 재고updatedAt (LocalDateTime) : 수정 시간productId(Long) :상품 IDprice (int) : 상품 가격description (String) : 상품 설명category (Category) : 카테고리productCondition (Condition) : 상품 상태options (List<optionGroup): 상품 옵션 그룹 목록optionGroupName (String) : 옵션 그룹명optionValues (List<String): 옵션 값 목록value (String): 옵션 값stock (int) : 재고updatedAt (LocalDateTime) : 수정 시간DELETE/products/{productId}adminToken (String) : 관리자 토큰productId (Long) : 상품 IDGET/productsproductId(Long) :상품 IDproductName (String) : 상품 이름price (int) : 상품 가격category (Category) : 카테고리productCondition (Condition) : 상품 상태GET/products/{productId}productId (Long) : 상품 IDproductId(Long) :상품 IDproductName (String) : 상품 이름price (int) : 상품 가격description (String) : 상품 설명category (Category) : 카테고리productCondition (Condition) : 상품 상태options (List<optionGroup): 상품 옵션 그룹 목록optionGroupName (String) : 옵션 그룹명 (예: "색상", "사이즈")optionValues (List<String): 옵션 값 목록여기서의 고민!
❓option을 어떻게 Entity로 구성할 것인가
일단 Entity로 option을 구성하는건 맞다. 상품 옵션을 저장할 때 상품이 무조건 있어야 한다. 그래서 내가 생각한 option의 Entity는
id (Long): 옵션 IDproductId (Product) : 상품 IDoptionTitle (String) : 옵션 이름optionValues (List<String) : 옵션 값이렇게 생각했다. 왜냐하면 나는 이렇게 했을 때의 장점이
- 옵션 값이 리스트로 저장되어 조회가 쉬움
예를 들어 "색상" 옵션에는 ["빨강", "파랑", "검정"] 같은 값을 한 줄(row)에 저장
"사이즈" 옵션에는 ["230", "240", "250"]을 저장 가능
이렇게 되기 때문에 더 관리하기 편하다고 생각했다. 하지만 이 Entity의 문제는
- optionValues가
List<String>로 JSON 형태로 저장되므로, SQL에서 직접 검색하거나 조인하기 어려움
예를 들어 "빨강" 옵션에 대한 재고(stock) 를 관리해야 한다면 어려움
그렇다,, 그래서 나는 Product / ProductOptionGroup / ProductOption 이렇게 관리하는게 좋을 것 같다.

이런식으로 관계를 매핑해준 다음에 엔티티를 구성했다.
id (Long) : 상품 IDname (String) : 상품 이름price (int) : 상품 가격description (String) : 상품 설명category (Category) : 카테고리productCondition (Condition) : 상품 상태isDeleted (boolean) : 삭제 여부createdAt (LocalDateTime) : 상품 등록 일시updatedAt (LocalDateTime) : 상품 정보 수정 일시reviewCount (int) : 리뷰 수isOnSale (boolean) : 판매 중 여부isPrivate (boolean) : 비공개productOptions (List<ProductOption) : 상품 옵션id (Long) : 옵션 IDproduct (Product) : 상품optionGroupName (String) : 상품 옵션 이름optionDetails (List<ProductOptionDetail>) : 상품 옵션 이름의 값 id (Long) : 옵션 디테일 IDoptionGroupName (ProductOption) : 상품 옵션 이름optionValue (String) : 상품 옵션 이름의 값 stock (int) : 재고이렇게 Entity들을 설계했다.
❓또 고민
1:N관계가 계속해서 중첩이 된다. 이게 맞나....?option과 optionDetail이 한번에 저장되고 싶다
예를 들어, 색상이 빨간색인 신발의 사이즈가 230인 상품의 재고가 3개 남은걸 저장하고 싶다.
그럼,@ElementCollection으로 아예 처음부터 종속적으로 저장해도 될까?
일단, ElementCollection은 완전 종속적인 관계일 때만 사용한다.
예를 들어 인스타 게시물을 올릴 때 무조건 사진을 올려야되니까 @ElementCollection으로 할 수 있다.
근데 이 경우는 230의 재고가 만약 0이 된다면 품절처리로 바꿔야하고, 중간에 새로운 색상이 추가가 된다면 수정하기도 어렵다. 따라서 oneToMany로 사용해서 부모자식의 관계를 맺어줘야 하는 것 같다.
❓또또 고민
그럼 HasMap()을 사용해서 key는 optionName, value는 옵션 값을 저장해놓으면 되지 않을까?
지피티의 도움을 받아서 함 알아봤다.
HashMap 사용의 단점
Product, ProductOption, ProductOptionDetail 사이의 관계를 명확하게 정의해야함.❓왜 관계형 DB에서 HashMap보다는 객체 관계를 사용하는 것이 더 나은가?
관계형 데이터베이스에서는 데이터의
정규화가 중요하기에, Product, ProductOption, ProductOptionDetail 사이의 관계를 테이블 간 외래키로 연결하는 방식이 더 적합하다. 이렇게 하면 각 데이터의 일관성을 유지하고, 데이터베이스에서 제공하는 조인이나 인덱싱 등의 최적화 기능을 활용할 수 있다.
결국엔 Entity로 1:N관계로 맺어서 사용하는게 맞는 것 같다.
근데 나중에 되면 1:N의 관계도 끊어버린다고 한다. 너무 불필요한 1:N의 관계 때문에 데이터가 한번 접근하기 위해서는 여러가지를 찾고 찾고 찾아서 찾을 수 있기 때문이다. 일단 1:N의 관계로 맺어보고, 수정하는걸로 해보자