Notice
Recent Posts
Recent Comments
Link
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
Tags
more
Archives
Today
Total
관리 메뉴

forDevLife

QueryDSL로 한 방 쿼리 작성하기 본문

JPA

QueryDSL로 한 방 쿼리 작성하기

JH_Lucid 2022. 6. 22. 19:51

 

이번 과제에서 위와 같은 이슈 조회를 위한 한 방 쿼리 작성을 시도했다. 특이사항으로는 label이 여러 개가 붙을 수 있다는 점이다.

아래에서 파란색은 조인된 관계를 의미하며, 빨간색은 DTO에 매핑될 컬럼을 의미한다.

Issue와의 관계를 분석하면 다음과 같다.

  • Issue : user = N : 1
  • Issue : milestone = N : 1

Issue와 label은 N:M(다대다) 관계이기 때문에 중간에 attached_label 테이블을 통해 관계를 1:N, N:1로 풀었다.

  • Issue : attached_label = 1 : N
  • attached_label : label = N : 1

 

한 방 쿼리를 위해서는 N : 1, 1 : N 관계 모두 FetchJoin을 통해 한 번에 가져올 수 있다. 

하지만 Issue, label처럼 다대다로 인한 중간 테이블이 있을 경우에는 어떻게 해야할까? 

간단하다. Issue : attached_label = 1 : N을 FetchJoin하고, attached_label : label = N : 1을 FetchJoin하면 된다.

 

이 방식을 통해 아래와 같이 Issue -> AttachedLabel -> Label로 추가 쿼리 없이 탐색이 가능해진다.

 

앞서 빨간색으로 표시한 정보를 통해 만들고자 하는 DTO는 다음과 같다.

 

LabelCoverResponse : label의 정보를 가지는 DTO

@ToString
@Getter
public class LabelCoverResponse {

    private String labelName;
    private String labelColor;
    private String textColor;

    public LabelCoverResponse(String labelName, String labelColor, String textColor) {
        this.labelName = labelName;
        this.labelColor = labelColor;
        this.textColor = textColor;
    }
}

 

 

IssueCoverResponse : LabelCoverResponse를 List로 가지고 있는 DTO

@ToString
@Getter
public class IssueCoverResponse {

    private List<LabelCoverResponse> labelCoverResponses;
    private String title;
    private Long issueId;
    private String writer;
    private String writerImage;
    private LocalDateTime modificationTime;
    private String milestoneName;   
}

 

 

 

방법 1. Issue로 모두 조회 후 DTO로 매핑


다음과 같이 Issue로 필요한 모든 내용을 가져온 후, Application level에서 DTO로 변형하는 방법이 제일 Simple하다.

 

1) Querydsl을 통해 IssueList를 조회한다.

앞과 동일한 코드이다.

 

2) Application level에서 DTO로 변환한다.

 

 

 

하지만, 이 방식에서는 FetchJoin으로 인해 매핑되지 않을 컬럼도 모두 조회가 된다. 실제 나가는 select 절을 보면 상당히 길다.

 

 

방법 2 : 처음부터 DTO로 매핑


column에서 DTO에 매핑할 컬럼만 가져올 수 있다. transform & groupBy 조합을 사용하며, 이는 Querydsl에서 제공하는 Result Aggregation(결과 집합) 기능이다. groupBy는 다음 패키지에 존재한다.

import static com.querydsl.core.group.GroupBy.groupBy;

 

transform을 사용하면 groupBy에 지정된 key를 기준으로 list를 만들 수 있게 된다. 

위에서는 issue.id를 기준으로 그룹화하겠다는 의미이다. fetchJoin()이 아님에 유의하자.

 

 

위의 결과로 생성된 쿼리의 결과는 다음과 같으며, transform에서 지정한 컬럼만 가져옴을 알 수 있다.

위와 같이 가져온 데이터를 issue_id별로 그루핑하여 DTO에 매핑하게 된다.

같은 issue_id 그룹 내에서는 Label 관련 컬럼(label_name, label_color, label_text_color)만 다름에 유의하자! 따라서 위와 같이 DTO 내의 List로 매핑이 가능해진다.

 

 

해당 방법을 사용한 최종 조회 결과는 다음과 같다.

 

 

다만, label정보가 없을 경우에는 아래처럼 null로 채워짐을 알 수 있다. 

 

 

 

참고


  • list().as()를 통해 alias를 지정할 수 있는 것 같는데, 이걸 하면 projection 오류가 발생한다. 따로 지정 안하니 해결되었다.
 

QueryDsl Projection List 쿼리 생성

QueryDsl Projections 을 사용해서 1:N 관계의 List<Object> 를 추출하는 코드를 작성해보자. 부모 DTO @Getter @Setter @AllArgsConstructor @NoArgsConstructor public class ParentDto { private UUID id; private String name;

bbuljj.github.io

 

 

@QueryProjection과 fetch join - 인프런 | 질문 & 답변

List<ProjectionResult> fetch = queryFactory .select(new QProjectionResult(classA.id, classA.relStatus.stringValue(), ...

www.inflearn.com

 

 

Querydsl 에서 OneToMany 관계에서 Left Outer Join 이 필요할 경우

안녕하세요? 이번 시간에는 JPA와 Querydsl을 사용하실때 OneToMany 관계에서 Left Join (Outer Join) 이 필요할 경우 어떻게 하면 될지에 대해서 소개 드리겠습니다. 모든 코드는 Github에 있으니 필요시 참고

jojoldu.tistory.com

 

'JPA' 카테고리의 다른 글

[JPA] @ElementCollection  (0) 2021.11.21
Comments