대충 넘어가지 않는 습관을 위한 기록

Querydsl - DTO 반환

uhyvn 2024. 5. 2. 21:11

김영한님의 실전! Querydsl 를 보고 기록한 글입니다.

 

 


 

 

 

멤버 Dto

@Data
public class MemberDto {

   private String username;
   private int age;
   
   public MemberDto() {
   }
   
}

 

 

 

 

 

 

 

순수 JPA에서 DTO를 조회하는 방법

List<MemberDto> result = em.createQuery(
 	"select new study.querydsl.dto.MemberDto(m.username, m.age) " +
 			"from Member m", MemberDto.class)
 	.getResultList();
  • 순수 JPA에서 DTO를 조회할 때는 new 명령어를 사용해야함
  • DTO의 package이름을 다 적어줘야해서 지저분함
  • 생성자 방식만 지원함

 

 

 


 

 

 

 

 

Querydsl로 결과를 DTO 반환할 때, 다음 4가지 방법 지원

  • 프로퍼티 접근
  • 필드 직접 접근
  • 생성자 사용
  • + 1가지!

 

 

 

프로퍼티 접근 - Setter

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

 

 

 

 

 

필드 직접 접근

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

주의! - 필드명이 같아야 함

만약 username이 아닌 name이었다면 name은 전부 null로 조회된다.

다른 해결 방안으로 member.username.as("name")  <- 이렇게 as를 이용한 방법도 있다.

 

그러나 서브쿼리같은 경우는 아래와 같이 ExpressionUtils를 써야한다.

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();

 

 

 

 

 

생성자 사용

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

 

 

 

 

 

생성자 + @QueryProjection

이 방법은 멤버 Dto에 @QueryProjection을 붙여줘야 한다.

@Data
public class MemberDto {

 	private String username;
 	private int age;
 
 	public MemberDto() {
 	}
    
 	@QueryProjection
 	public MemberDto(String username, int age) {
 	this.username = username;
 	this.age = age;
 	}
    
}
  1. ./gradlew compileQuerydsl 실행
  2. QMemberDto 생성 확인 후 작성해야 함

 

 

@QueryProjection 활용

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

 

 

이 방법은 컴파일러로 타입을 체크할 수 있으므로 가장 안전한 방법이다.

다만 DTO에 QueryDSL 어노테이션을 유지 해야 하는 점과 DTO까지 Q 파일을 생성해야 하는 단점이 있다.