TIL ... day 26 5주차 - Spring 5일차 프로젝트 회고… 22.06.08

BYEONGMIN CHOI·2022년 6월 8일
0

TIL(Today I Learned)

목록 보기
16/24

5주차 과제를 하며 발생한 이슈에 대해 적어보려고 합니다.

5주차 과제는 주문 앱의 API를 구현하는 과제였습니다.

간단하게 음식점을 등록하고, 음식점 마다 요리를 등록하고 주문을 통해 주문된 음식의 수량 만큼 총액이 계산되는 API 설계였습니다.

아래 그림은 각 Entity 의 관계를 ERD로 나타낸 것입니다.

< Order - Restaurant 관계 : 다대일 >

  • Order 입장 - 한 주문에 하나의 Restaurant만 존재한다.
  • Restaurant 입장 - 한 Restaurant 에는 여러 주문이 존재할 수 있다.

< Restarant - Food 관계 : 다대일 >

  • Restaurant 입장 : 한 군데의 Restaurant 에서 여러 Food가 존재한다.
  • Food 입장 : 하나의 Food는 하나의 Restaurant에만 있다. (다른 음식점의 햄버거가 있어도 다른 요리로 제한조건이 있다.)

< Order - Food 관계 : 다대다 >

  • Order 입장 - 하나의 Order에 여러 Food가 담길 수 있다.
  • Food 입장 - 하나의 Food는 여러 Order에 담길 수 있다.
    -> N : M의 관계를 1 : N , M : 1 의 관계로 풀어 설계하였다.

위의 관계를 적용하여 객체간의 연관관계 매핑을 하였으며, OrderFood 라는 객체를 생성하여 다대다 관계를 일대다 다대일 관계로 풀어주었습니다.

양방향 매핑시 실수...

Order를 조회하는 API를 설계하면서 이슈가 발생하였다. 아래 코드가 조회를 처리해주는 OrderService 이다.

 @Transactional
    public OrderDto requestOrder(OrderRequestDto orderRequestDto) {

        // OrderDto => Order Response
        Restaurant restaurant = restaurantRepository.findById(orderRequestDto.getRestaurantId()).orElseThrow(
                () -> new IllegalArgumentException("음식점이 등록되어 있지 않습니다."));

        List<OrderFoodDto> orderFoodDtoList = new ArrayList<>(); // response list
        List<OrderFood> orderFoodList = new ArrayList<>(); // DB 저장 list

        // TODO: 2022/06/08
        // order 를 영속성 컨텍스트에 order를 저장하여 테이블에 반영
        Order order = new Order();
        orderRepository.save(order);

        int totalPrice = 0;

        for (OrderFoodRequestDto orderFoodRequestDto : orderRequestDto.getFoods()) {
            Food food = foodRepository.findByIdAndRestaurant(orderFoodRequestDto.getId(), restaurant).orElseThrow(
                    ()-> new IllegalArgumentException("주문하신 음식은 등록되어 있지 않습니다."));

            if(orderFoodRequestDto.getQuantity() < 1 || orderFoodRequestDto.getQuantity() > 100){
                throw new IllegalArgumentException("주문한 음식의 수량을 확인해 주세요. 1 ~ 100개 까지만 주문이 가능합니다.");
            }

            // OrderFood entity 저장
            OrderFood orderFood = new OrderFood(food, orderFoodRequestDto.getQuantity());
            order.addOrderFood(orderFood);
            orderFoodList.add(orderFood);
            orderFoodRepository.save(orderFood);
            orderRepository.save(order);

            OrderFoodDto orderFoodDto = new OrderFoodDto(food, orderFoodRequestDto);
            orderFoodDtoList.add(orderFoodDto);

            // 주문한 음식의 전체 금액 계산
            totalPrice += (food.getPrice() * orderFoodRequestDto.getQuantity());
        }

        if(totalPrice < restaurant.getMinOrderPrice()) throw new IllegalArgumentException("최소 주문 가격보다 적은 금액입니다.");

        // TODO: 2022/06/08
        order.setRestaurant(restaurant);
        order.setFoods(orderFoodList);
        order.setTotalPrice(totalPrice);
        orderRepository.save(order);

        return new OrderDto(restaurant, orderFoodDtoList, totalPrice);
    }

위 코드에서 초기에 새로운 Order 객체를 생성하여 OrderRepository에 저장하는 부분을 빼먹고 코드를 진행했었습니다. Order 와 OrderFood 는 양방향 매핑이므로 주인이 아닌 OrderFood를 저장하더라도 Order에 반영되지 않는 것을 알지 못하고 코드를 짰었다.

그결과 OrderFood 테이블의 ORDER_ID 가 null 로 데이터가 추가 되지 않았다.

따라서 초기에 새로운 Order 객체를 생성하여 repository에 저장하여 영속성 컨텍스트에 영속시켜 주었으며, 변경사항을 컬렉션과 Order 의 연관관계편의 메소드를 활용하여 양쪽 모두 값을 세팅하여 반영하여 이슈를 해결하였다. 김영한님 강의 중 가장많이하는 실수를 저질렀다...
아래는 연관관계 편의 메소드 이다.

@Entity
@Table(name = "orders")
@Getter
class Order{
	
    ...
    
    // 연관 관계 편의 메소드
    public void addOrderFood(OrderFood orderFood){
        foods.add(orderFood);
        orderFood.setOrder(this);
    }
 }

참고 : https://velog.io/@chois90/Spring-ORM-JPA-관련-정리-2

profile
스스로 성장하는 개발자가 되겠습니다.

0개의 댓글