인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

인프런 커뮤니티 질문&답변

Sunny님의 프로필 이미지
Sunny

작성한 질문수

실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화

OneToMany Many쪽의 페이지네이션 질문입니다

작성

·

705

0

안녕하세요? 섹션 4 강의 컬렉션 조회 페이징을 보고 질문 드립니다. 주문 조회 V3.1에서 페이징을 위해

jpa.properties.hibernate.default_batch_fetch_size=100, @BatchSize를 사용하거나 또는

V5에서 Map, groupBy를 이용하여 DTO 직접 조회Order에 대하여 페이징이 가능하다는 것을 알았습니다.

그런데 만약 Order 페이징 + OrderItem 페이징(예를 들어 주문을 10건 중 비싼 아이템 2건만 조회하기)같은 경우에는 어떻게 적용이 가능한가요?

public List<OrderQueryDto> findAllOpt(){
		List<OrderQueryDto> result = findOrders(); // 기존의 ToOne 쿼리

		List<Long> orderIds = result.stream()      // in 쿼리를 위한 id 뽑기
							.map(o -> o.getOrderId())
							.collect(Collectors.toList());
		
		List<OrderItemQueryDto> orderItems = findMap(orderIds);

		Map<Long, List<OrderItemQueryDto>> orderItemMap = orderItems.stream()
							.collect(Collectors.groupingBy(OrderItemQueryDto::getOrderId));	
		
		result.forEach(o -> o.setOrderItems(orderItemMap.get(o.getOrderId())));
		return result;
}

public List<OrderItemQueryDto> findMap(List<Long> orderIds) {
		return em.createQuery(
					"select new queryDto(파라미터들)" +
					" from OrderItem oi" +
					" join oi.item i" +
					" where oi.order.id in :orderIds", OrderItemQueryDto.class)
                                           .setFirstResult(0)
                                           .setMaxResults(2)
					.setParameter("orderIds", orderIds)
					.getResultList();
		)
}

이렇게 Limit를 걸었을 때 UserA 2건 뜨고 UserB는 null 이 뜨더군요. 

다른 방법을 찾아본 결과 https://bottom-to-top.tistory.com/45 처럼 방향을 반대로 하여 ManyToOne으로 조회하는 방법도 있다는것을 알았습니다.

결국엔 Order 페이징 + OrderItem 페이징 까지 접목시키려면 ManyToOne으로 조회하는 방법밖에 없을까요?

답변 2

1

Sunny님의 프로필 이미지
Sunny
질문자

아 그런 마법의 코드 같은건 없군요 감사합니다 어떻게 해야할지 확실히 정해졌어요!

1

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. Sunny님

이 부분은 JPA의 문제라기 보다는 관계형 데이터베이스의 한계입니다. OneToMany 관계를 조인하면 데이터가 증가해서 정확한 페이징이 불가능합니다.

반대로 ManyToOne 관계를 조인하면 데이터수가 증가하지 않기 때문에 정확한 페이징이 가능합니다.

감사합니다.

Sunny님의 프로필 이미지
Sunny

작성한 질문수

질문하기