도메인 분석 설계
<aside>
❗
요구사항 분석
[기능 SS목록]
도메인 모델과 테이블 설계
[회원, 주문, 상품의 관계]
- 회원은 여러 상품을 주문할 수 있다. 그리고 한 번 주문할 때 여러 상품을 선택할 수 있으므로
주문과 상품은 다대다 관계다.
- 하지만 이런 다대다 관계는 관계형 데이터베이스는 물론이고 엔티티에서도 거의 사용하지 않는다. 따라서 그림처럼 주문상품이라는 엔티티를 추가해서 다대다 관계를 일대다, 다대일 관계로 풀어냄
[상품 분류]
- 상품은 도서, 음반, 영화로 구분되는데 상품이라는 공통 속성을 사용하므로 상속 구조로 표현
회원 엔티티 분석
- 잘 보면, JPA에서 표현할 수 있는 모든 관계가 설정되어 있음
- 회원이 통해서 주문이 가능하다 보다.
주문을 생성할 때, 회원이 필요하다고 봐야 한다.
- 주문 내역이 필요하면 Member를 찾아서 orders 리스트에서 찾아오는게 아니라
주문이 필요하면 Order에서 필터링 조건에 Member가 들어가면 됨
- 즉, Member와 Order 양방향 관계는 필요하지 않음
다양한 예제를 위해 이렇게 설계된 것
[회원]
- 이름과 임베디드 타입인 주소(
Address
), 그리고 주문(orders
) 리스트를 가진다.
- 임베디드 타입이란 JPA에서 엔티티(Entity) 내부에 포함될 수 있는
값 타입(Value Type)을 정의하기 위해 사용하는 클래스
[주문]
- 한 번 주문시 여러 상품을 주문할 수 있으므로 주문과 주문상품(
OrderItem
)은 일대다 관계다
- 주문은 상품을 주문한 회원과 배송 정보, 주문 날짜, 주문 상태(
status
)를 가지고 있다.
- 주문 상태는 열거형을 사용했는데 주문(
ORDER
), 취소(CANCEL
)을 표현할 수 있다.
[주문 상품]
- 주문한 상품 정보와 주문 금액(
orderPrice
), 주문 수량(count
) 정보를 가지고 있다.
- (보통
OrderLine
, LineItem
으로 많이 표현한다.)
[상품]
- 이름, 가격, 재고수량(
stockQuantity
)을 가지고 있다. 상품을 주문하면 재고수량이 줄어든다.
- 상품의 종류로는 도서, 음반, 영화가 있는데 각각은 사용하는 속성이 조금씩 다르다.
[배송]
- 주문시 하나의 배송 정보를 생성한다. 주문과 배송은 일대일 관계다.
[카테고리]
- 상품과 다대다 관계를 맺는다.
parent
, child
로 부모, 자식 카테고리를 연결한다.
[주소]
- 값 타입(임베디드 타입)이다. 회원과 배송(Delivery)에서 사용한다.
참고
- 회원 엔티티 분석 그림에서 Order와 Delivery가 단방향 관계로 잘못 그려져 있다. 양방향 관계가 맞다.
- 회원이 주문을 하기 때문에, 회원이 주문리스트를 가지는 것은 얼핏 보면 잘 설계한 것 같지만,
- 객체 세상은실제 세계와는 다르다. 실무에서는 회원이 주문을 참조하지 않고, 주문이 회원을 참조하는 것으로 충분하다.
- ** 다대다 관계는 실무에서 사용하면 안된다.
→ 1 대 다, 다 대 1로 풀어내야 함.
- 양방향 연관관계를 쓰지 않는 것이 좋다.
- 여기서는 일대다, 다대일의 양방향 연관관계를 설명하기 위해서 추가했다.
회원 테이블 분석
[Member]
- 회원 엔티티의
Address
임베디드 타입 정보가 회원 테이블에 그대로 들어갔다.
이것은 DELIVERY
테이블도 마찬가지다.
[ITEM]
- 앨범, 도서, 영화 타입을 통합해서 하나의 테이블로 만들었다.
DTYPE
컬럼으로 타입을 구분한다.
[참고]
- 테이블명이
ORDER
가 아니라 ORDERS
인 것은 데이터베이스가 order by
때문에
예약어로 잡고 있는 경우가 많다. 그래서 관례상 ORDERS
를 많이 사용한다.
- 실제 코드에서는 DB에 소문자 + _(언더스코어) 스타일을 사용하겠다.
데이터베이스 테이블명, 컬럼명에 대한 관례는 회사마다 다르다.
- 보통은 대문자 + _(언더스코어)나 소문자 + _(언더스코어) 방식 중에 하나를 지정해서
일관성 있게 사용한다.
- 강의에서 설명할 때는 객체와 차이를 나타내기 위해데이터베이스 테이블, 컬럼명은 대문자를 사용했지만, 실제 코드에서는 소문자 + _(언더스코어) 스타일을 사용하겠다.
연관관계 매핑 분석
[회원과 주문]
- 일대다 , 다대일의 양방향 관계다. 따라서 연관관계의 주인을 정해야 하는데,
외래 키가 있는 주문을 연관관계의 주인으로 정하는 것이 좋다.
그러므로
Order.member
를 ORDERS.MEMBER_ID
외래 키와 매핑한다.
[주문상픔과 주문]
- 다대일 양방향 관계다. 외래 키가 주문상품에 있으므로 주문상품이 연관관계의 주인이다.
그러므로
OrderItem.order
를 ORDER_ITEM.ORDER_ID
외래 키와 매핑한다.
[주문상품과 상품]
- 다대일 단방향 관계다.
OrderItem.item
을 ORDER_ITEM.ITEM_ID
외래 키와 매핑한다.
[주문과 배송]
- 일대일 양방향 관계다.
Order.delivery
를 ORDERS.DELIVERY_ID
외래 키와 매핑한다.
[카테고리와 상품]
- @ManyToMany` 를 사용해서 매핑한다.(실무에서 @ManyToMany는 사용하지 말자.
여기서는 다대다 관계를 예제로 보여주기 위해 추가했을 뿐이다)
- 객체는 양쪽다 컬렉션을 가져서 다대다 관계를 만들 수 있다.
하지만 관계형 데이터베이스는 일반적인 설계로 그게 안 됨
그래서 매핑 테이블(CATEGORY_ITEM 테이블)을 둬서
다대다 관계를 일대다, 다대일 관계로 풀어야 한다.
참고
- 외래 키가 있는 곳을 연관관계의 주인으로 정해라.
- 연관관계의 주인은 단순히 외래 키를 누가 관리하냐의 문제이지 비즈니스상 우위에 있다고 주인으로 정하면 안된다..
- 예를 들어서 자동차와 바퀴가 있으면, 일대다 관계에서 항상 다쪽에 외래 키가 있으므로 외래 키가 있는 바퀴를 연관관계의 주인으로 정하면 된다. 물론 자동차를 연관관계의 주인으로 정하는 것이 불가능 한 것은 아니지만, 자동차를 연관관계의 주인으로 정하면 자동차가 관리하지 않는
바퀴 테이블의 외래 키 값이 업데이트 되므로 관리와 유지보수가 어렵고,
추가적으로 별도의 업데이트 쿼리가 발생하는 성능 문제도 있다.
자세한 내용은 JPA 기본편을 참고하자.
</aside>