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
관리 메뉴

DOing

[Querydsl] 튜플이나 DTO로 결과 반환하기 본문

JPA

[Querydsl] 튜플이나 DTO로 결과 반환하기

mangdo 2021. 8. 5. 00:55

 

프로젝션 : select 대상지정하는 일

프로젝션 대상이 두개 이상이라면 튜플이나 DTO로 조회해야한다.

 

🌱 튜플 사용하기

com.querydsl.core.Tuple를 사용하고 있다.

때문에 Repository 계층을 넘어서 Service나 Controller계층에 넘어가는 것은 좋지않은 설계다.
Service나 Controller계층에 넘어갈때는 DTO로 넘어가는 것이 좋다고 생각한다.

List<Tuple> result = queryFactory
                        .select(member.username, member.age)
                        .from(member)
                        .fetch();

for (Tuple tuple : result) {
    String username = tuple.get(member.username);
    Integer age = tuple.get(member.age);
    
    System.out.println("username=" + username);
    System.out.println("age=" + age);
}

 

🌱 DTO 사용하기

DTO를 사용하려면 다음 3가지 방법 지원한다.

  • 프로퍼티 접근
  • 필드 직접 접근
  • 생성자 사용

 

1. Bean() -> getter, setter, 디폴트 생성자 필요

List<MemberDto> result = queryFactory
                          .select(Projections.bean(MemberDto.class,
                                        member.username,
                                        member.age))
                          .from(member)
                          .fetch();

2. 필드 직접 접근 -> getter, setter필요없음. 바로주입

List<MemberDto> result = queryFactory
                        .select(Projections.fields(MemberDto.class,
                                    member.username,
                                    member.age))
                        .from(member)
                        .fetch();

3. 생성자 사용

List<MemberDto> result = queryFactory
                            .select(Projections.constructor(MemberDto.class,
                                      member.username,
                                      member.age))
                            .from(member)
                            .fetch();

 

번외 ) DTO의 이름이 다르다면?

ExpressionUtils.as(source,alias)-> 필드나, 서브 쿼리에 별칭 적용

List<UserDto> fetch = queryFactory
                        .select(Projections.fields(UserDto.class,
                                member.username.as("name"),
                                ExpressionUtils.as(
                                    JPAExpressions
                                    .select(memberSub.age.max())
                                    .from(memberSub), "age")
                                ))
                        .from(member)
                        .fetch();

 

4. @QueryProjection

DTO 생성자에 @QueryProjection을 붙여주면 DTO도 Q파일로 생성된다.

import com.querydsl.core.annotations.QueryProjection;

public class MemberDto {

    private String username;

    private int age;

    public MemberDto() {
    }

    @QueryProjection
    public MemberDto(String username, int age) {
        this.username = username;
        this.age = age;
    }
}

생성된 Q파일을 사용하면된다.

queryFactory
    .select(new QMemberDto(member.username, member.age))
    .from(member)
    .fetch();

-> 이 방법의 좋은점은 컴파일오류로 많은 것을 잡아낼 수 있다는 것이다.

-> 컴파일 시점에 타입 체크, 파라미터 갯수체크 등 가능하다.

-> 단, memberDto가 Querydsl에 대한 의존성이 생긴다는 단점이 있다.

    특히 DTO는 Service계층, Controller계층등 여러 계층을 넘어다니는 객체임으로 아키텍쳐 전반적으로 Querydsl에 대한 의존성이 생기는 것이 큰 단점이 생길 수 있다. 

 

 

'JPA' 카테고리의 다른 글

[JPA] JPQL이란?  (0) 2021.08.08
[JPA] Fetch Join  (1) 2021.08.06
[Querydsl] 서브쿼리  (0) 2021.08.04
[Querydsl] Join  (0) 2021.08.04
[Querydsl] 정렬, 페이징, 집계 함수, 그룹 함수  (0) 2021.08.04