Skip to content

JPA Section5‐6

SH-Seol edited this page May 25, 2024 · 1 revision
@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class ItemService {
    private final ItemRepository itemRepository;

    @Transactional
    public void saveItem(Item item){
        itemRepository.save(item);
    }

    public List<Item> findItems(){
        return itemRepository.findAll();
    }

    public Item findOne(Long itemId){
        return itemRepository.findOne(itemId);
    }
5-6
  • saveItem은 반드시 Transactional을 해야하는 것 잊지 말자. 안그러면 저장 안된다!
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class OrderService {
    private final OrderRepository orderRepository;
    private final MemberRepository memberRepository;
    private final ItemRepository itemRepository;

    /**
     * 주문
     */
    @Transactional
    public Long order(Long memberId, Long itemId, int count){
        Member member = memberRepository.findOne(memberId);
        Item item = itemRepository.findOne(itemId);

        Delivery delivery = new Delivery();
        delivery.setAddress(member.getAddress());

        OrderItem orderItem = OrderItem.createOrderItem(item, item.getPrice(), count);
				
				//1. OrderItem orderItem1 = new OrderItem();
				//OrderItem1.setCount();
				
        Order order = Order.createOrder(member, delivery, orderItem);

        //주문 저장
        orderRepository.save(order);

        return order.getId();
    }
}
  • 1번이 안되는 이유는 퍼져 있다 보니, 나중에 유지보수가 매우 어려워짐.

    • 막는방법: protected 생성자
    • Or OrderItem, Order에@NoArgsConstructor(access=AccessLevel.PROTECTED)
  • 엔티티가 비즈니스 로직을 가지고 객체 지향의 특성을 적극 활용하는 것 → 도메인 모델 패턴

  • 엔티티에 비즈니스 로직이 거의 없고 서비스 계층에서 대부분의 비즈니스 로직을 처리하는 것 → 트랜잭션 스크립트 패턴

  • 한 프로젝트 안에서 둘 다 같이 사용될 수 있음. 문맥에 따라 선택

  • test는 단위테스트가 정말 좋은 테스트.

JPA에서 동적 쿼리 처리

방법 1

String jpql = "select o from Order o join o.member m";
        boolean isFirstCondition = true;
        
        if(orderSearch.getOrderStatus() != null){
            if(isFirstCondition){
                jpql += "where";
                isFirstCondition = false;
            }else{
                jpql += "and";
            }jpql += "o.status = :status";
        }
        if (StringUtils.hasText(orderSearch.getMemberName())){
            if (isFirstCondition){
                jpql += "where";
                isFirstCondition = false;
            }else{
                jpql += "and";
            }
            jpql += "m.name like :name";
        }
        TypedQuery<Order> query = em.createQuery(jpql, Order.class)
                .setMaxResults(1000);
        if(orderSearch.getOrderStatus() != null){
            query = query.setParameter("status", orderSearch.getOrderStatus());
        }
        if(StringUtils.hasText(orderSearch.getMemberName())){
            query = query.setParameter("name", orderSearch.getMemberName());
        }
        return query.getResultList();
  • 버그가 가득

방법2

public List<Order> findAllByCriteria(OrderSearch orderSearch){
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<Order> cq = cb.createQuery(Order.class);
        Root<Order> o = cq.from(Order.class);
        Join<Object, Object> m = o.join("member", JoinType.INNER);
        
        List<Predicate> criteria = new ArrayList<>();
        
        if(orderSearch.getOrderStatus()!= null){
            Predicate status = cb.equal(o.get("status"), orderSearch.getOrderStatus());
            criteria.add(status);
        }
        if (StringUtils.hasText(orderSearch.getMemberName())){
            Predicate name =
                    cb.like(m.<String>get("name"), "%" + orderSearch.getMemberName() + "%");
            criteria.add(name);
        }
        cq.where(cb.and(criteria.toArray(new Predicate[criteria.size()])));
        TypedQuery<Order> query = em.createQuery(cq).setMaxResults(1000);
        return query.getResultList();
  • 이건 사람이 유지보수 할 수 없다.

방법3(Querydsl)