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

프로젝션 : 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 |