본문 바로가기
JPA

JPA 주문 도메인 개발

by ppirae 2022. 4. 20.

주문 도메인 개발

1. 주문, 주문상품 엔티티 개발

 

생성 메서드( createOrder() ): 주문 엔티티를 생성할 때 사용한다. 주문 회원, 배송정보, 주문상품의 정보를 받아서 실제 주문 엔티티를 생성한다.

주문 취소( cancel() ): 주문 취소시 사용한다. 주문 상태를 취소로 변경하고 주문상품에 주문 취소를 알린다. 만약 이미 배송을 완료한 상품이면 주문을 취소하지 못하도록 예외를 발생시킨다.

전체 주문 가격 조회: 주문 시 사용한 전체 주문 가격을 조회한다. 전체 주문 가격을 알려면 각각의 주문상품 가격을 알아야 한다. 로직을 보면 연관된 주문상품들의 가격을 조회해서 더한 값을 반환한다. (실무에서는 주로 주문에 전체 주문 가격 필드를 두고 역정규화 한다.)

 

주문취소인 cancel 에서는 addStock을 한다.

public void addStock(int quantity) {
    this.stockQuantity += quantity;
}

주문생성인 createOrder에서는 removeStock을 한다.

public void removeStock(int quantity) {
    int restStoock = this.stockQuantity - quantity;
    if (restStoock < 0) {
        throw new NotEnoughStockException("need more stock");
    }
    this.stockQuantity = restStoock;
}

 

2. 주문 리포지토리 개발

나머지는 전과 동일

검색기능은 동적 쿼리가 들어가기때문에 마지막에 정리 

 

3. 주문 서비스 개발

CASCADE 옵션을 사용하면

orderRepository.save(order)만 해주어도 delivery와 orderItem 등이 모두 persist된다.

 

내가 개발할 때와 다르게 다른 사람이 개발할 때는 new 로 객체를 생성할 수 있다.

이때 기본 생성자를 protected로 설정하여 new 생성을 막아줄 수 잇다.

protected OrderItem() {
}

lombok으로 @NoArgsConstructor(access = AccessLevel.PROTECTED) 로 적어도 같은 기능이다.

 

JPA의 강점 : dirty checking(변경내역감지)하여 업데이트 쿼리를 날린다.

참고: 주문 서비스의 주문과 주문 취소 메서드를 보면 비즈니스 로직 대부분이 엔티티에 있다. 서비스 계층은 단순히 엔티티에 필요한 요청을 위임하는 역할을 한다. 이처럼 엔티티가 비즈니스 로직을 가지고 객체 지향의 특성을 적극 활용하는 것을 도메인 모델 패턴이라 한다.
반대로 엔티티에는 비즈니스 로직이 거의 없고 서비스 계층에서 대부분 의 비즈니스 로직을 처리하는 것을 트랜잭션 스크립트 패턴이라 한다

 

4. 주문 기능 테스트

상품주문( )

assertEquals("상품 주문시 상태는 ORDER", OrderStatus.ORDER, getOrder.getStatus());
assertEquals("주문한 상품 종류 수가 정확해야 한다.", 1, getOrder.getOrderItems().size());
assertEquals("주문 가격은 가격 * 수량 이다.", 10000 * orderCount, getOrder.getTotalPrice());
assertEquals("주문 수량만큼 재고가 줄어야 한다.", 8, book.getStockQuantity());

 

상품주문_재고수량초과( )

assertEquals("상품 주문시 상태는 ORDER", OrderStatus.ORDER, getOrder.getStatus());
assertEquals("주문한 상품 종류 수가 정확해야 한다.", 1, getOrder.getOrderItems().size());
assertEquals("주문 가격은 가격 * 수량 이다.", 10000 * orderCount, getOrder.getTotalPrice());
assertEquals("주문 수량만큼 재고가 줄어야 한다.", 8, book.getStockQuantity());

 

주문취소( )

assertEquals("주문 취소시 상태는 CANCEL 이다.", OrderStatus.CANCEL, getOrder.getStatus());
assertEquals("주문이 취소된 상품은 그만큼 재고가 증가해야 한다.", 10, item.getStockQuantity());

 

(실제 실무에서는 이거보다 훨씬 꼼꼼하게 만듬. 정말 좋은 테스트는 단위테스트)

//ctrl + alt + m : extract method

//ctrl + alt + p : parameter 꺼내기

 

5. 주문 검색 기능 개발

JPA에서 동적 쿼리를 어떻게 해결해야 하는가?

 

첫번째 무식한 방법) JPQL을 상황에 따른 문자로 해결한다.

-> 정말 복잡하고 실수가 많고 유지보수가 어렵다.

 

두번째 방법) Criteria 이용 (Criteria -> JPQL을 작성할 수 있게 JPA에서 표준으로 제공해 주는 것)

-> 읽는사람이 멘붕, 유지보수성이 제로에 가깝다 (실무에서 전혀 사용하지않음)

 

세번째 방법) 가장 멋진 해결책은 Querydsl이다.

Querydsl 강의에서 설명하기로 하고 넘어감...

 

실무는

Spring Boot + Spring data JPA + JPA + Querydsl 은 함께 가져간다. 


인프런 김영한님의 스프링부트와 JPA 활용1을 듣고 작성한 글입니다.

https://inf.run/uqB6

 

실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발 - 인프런 | 강의

실무에 가까운 예제로, 스프링 부트와 JPA를 활용해서 웹 애플리케이션을 설계하고 개발합니다. 이 과정을 통해 스프링 부트와 JPA를 실무에서 어떻게 활용해야 하는지 이해할 수 있습니다., - 강

www.inflearn.com

 

'JPA' 카테고리의 다른 글

JPA에 대해..  (0) 2022.05.09
JPA 웹 계층 개발 - 홈 화면과 레이아웃  (0) 2022.04.22
JPA 회원, 상품 도메인 개발  (0) 2022.04.19
JPA 도메인 분석 설계  (0) 2022.04.19
JPA 프로젝트 환경설정  (0) 2022.04.17

댓글