inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

실전! Querydsl

2개 이상의 OneToMany 관계에서 fetch join 문제

1913

김싸피

작성한 질문수 1

0

안녕하세요 영한님!

좋은 강의 너무너무 잘 듣고 있습니다!

다름이 아니라 JPA와 Querydsl을 공부하던 중 궁금한 점이 생겨 이렇게 질문을 드립니다.

OneToMany 관계에서는 N+1 문제를 해결하기 위해 fetch join을 사용해 자식 엔티티도 모두 함께 가져오는 것으로 배웠습니다.

만약 아래처럼 하나의 엔티티와 자식 엔티티, 자식 엔티티의 자식 엔티티가 모두 OneToMany 관계인 경우 최상위 엔티티를 가져올 때 한꺼번에 모든 자식 엔티티를 가져올 수 있는 방법이 있는지 여쭤보고 싶습니다..!

@Entity
public class Forest{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "forest_id")
    private Long id;

    @OneToMany(mappedBy = "forest")
    private List<Tree> trees= new ArrayList<>();
}

@Entity
public class Tree{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "tree_id")
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "forest_id")
    private Forest forest;

    @OneToMany(mappedBy = "tree",  cascade = CascadeType.ALL)
    private List<Leaf> leaves= new ArrayList<>();
}

@Entity
public class Leaf{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "leaf_id")
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "Tree_id")
    private Tree tree;
}

위 코드를 기준으로 제가 원하는 것은 모든 Forest을 가져올 때, Forest의 자식인 Tree와 Tree의 자식인 Leaf를 함께 가져오는 것인데,

처음엔 단순히 fetch join을 두번 사용하면 될 것이라고 생각했습니다.

따라서 코드를 다음과 같이 작성했습니다.

public List<Forest> findAllFetch() {
        return queryFactory
                .selectFrom(forest)
                .leftJoin(forest.trees, tree).fetchJoin()
                .leftJoin(tree.leaves).fetchJoin()
                .fetch();
}

하지만 위 코드처럼 두개 이상의 OneToMany 관계에서 fetch join을 여러번 사용하면 MultipleBagFetchException이 발생했습니다. 

찾아보니 JPQL에서는 xToMany에서는 일반적으로 fetch join은 한번만 허용된다고 하더라구요...

따라서 제가 생각한 해결책은 위 과정을  2번의 쿼리로 나누어 실행시키는 방법이었습니다.


public List<Forest> findAllFetch() {
	List<Forest> result = queryFactory
                .selectFrom(forest).distinct()
                .leftJoin(forest.trees).fetchJoin()
                .fetch();

	List<Long> selectedIds = result.stream()
                .map(Forest::getId)
                .collect(Collectors.toList());

	queryFactory
                .selectFrom(tree).distinct()
                .leftJoin(tree.leaves).fetchJoin()
                .where(tree.forest.id.in(selectedIds ))
                .fetch();
    return result ;
}

혹시 위 코드보다 더 나은 방법이 있는지 아니면 한번의 쿼리로 모든 자식 엔티티를 받아올 수 있는 방법이 있는지 궁금합니다.

jpa querydsl java JPA

답변 1

0

김영한

안녕하세요. 김싸피님

한줄로 답변을 드릴 수 있으면 좋겠지만, 이 부분을 이해하려면 여러가지 성능 최적화 개념을 이해하셔야 합니다.

관련해서 실전! 스프링 부트와 JPA 활용2편 강의에서 상황별로 다양한 최적화 방법을 자세히 설명드립니다.

감사합니다.

0

김싸피

답변 감사합니다!!

따흐흑....ㅠㅠ  완강하고 얼른 활용 2편을 수강해야 할것 같네요.

0

김영한

네 화이팅^^!

SpringBoot 4.X에서의 Querydsl 설정

0

105

2

querydsl 오픈소스에 대한 질문

1

82

1

예제에서의 카운트 쿼리에서 join문과 where문은 필요없지 않나요?

0

114

1

Querydsl 6.X버전에 대해서 어떻게 생각하시나요?

0

326

2

여러 테이블 조인하여 통계치를 구하고자 할 때 어떤 방법이 더 효율적일까요

1

73

1

fetchResults()는 더이상 권장되지 않는다는데 맞나요?

0

164

1

querydsl sum() 메서드 없어요.

0

163

2

build 디렉터리 생성

0

142

2

자바 ORM 표준 JPA 프로그래밍 - 기본편 듣고 바로 학습해도 괜찮을까요?

0

116

2

현재 Querydsl에서 from절 서브쿼리를 지원하나요?

0

94

1

오타 제보 드립니다.

0

74

2

벌크 연산과 flush, clear

0

77

1

Run As Intellij 로 변경시 Q타입 import 불가

0

90

1

QHello import하기 문제 발생

0

150

2

등록된 함수 보는법(H2Dialect) 질문

0

70

2

5.0부터 Querydsl은 향후 fetchCount() , fetchResult() 를 지원하지 않기로 결정했다고 하는데 이에 맞는 강의

1

201

2

[환경설정 PDF 부트 3.0이후 설명 질문] build.gradle에 compileQuerydsl을 정의하지 않은 상태에서 Gradle->Tasks->other->compileQuerydsl을 클릭하라고 하는 이유가 무엇인가요??

1

203

1

querydsl 설정 문제

0

223

2

quey dsl 설정부분

0

159

2

count 쿼리 관련 질문입니다!

0

75

1

stringtemplate를 이용하여 where절 검색 방법 질문 드립니다.

0

90

1

답변부탁드리겠습니다.

0

91

2

(OrderSpecifier)관련 내용 어디있을가요

0

67

1

중급문법 벌크연산에서

0

84

2