본문 바로가기
JAVA/JPA

[QueryDSL] QueryDSL 문법 #3 - DTO 반환 방법

by 개미가되고싶은사람 2025. 2. 1.

이번 포스팅해서 기본 문법보다 조금 어려운 문법을 다룰 예정이라서 기본 문법은 아래 링크를 참조해주세요

https://pjstudyblog.tistory.com/110

 

 

 

DTO 반환 방법

1. 프로퍼티 접근 - Projections.bean()

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

Projections.bean()는 setter 프로퍼티가 있으면 setter를 통해서 접근을 하고 setter가 없다면 리플렉션으로 접근합니다.

 

 

2. 필드 접근 - Projections.fields()

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

엔티티에 있는 필드명과 DTO에 있는 필드는 동일해야 하며, 이름이 다른 경우에는 as() 메소드를 사용하여 DTO에 원하는 필드명을 입력해주면 됩니다.

 

3. 사용자 사용 - Projections.constructor

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

생성자를 통해서 값을 설정 단 DTO에 있는 필드 타입과 엔티티에 있는 타입이 동일해야 합니다

 

 

그럼 DTO를 반환할 때 서브쿼리를 어떻게 써야 될까요?? 서브쿼리의 명칭을 정해 DTO에 필드를 생성할 수 없기 때문에 ExpressionUtils를 이용해 이 문제를 해결할 수 있으며, ExpressionUtils는 DTO를 반환하는 QueryDSL에서 서브쿼리에 명칭을 지정할 수 있도록 도와주는 클래스입니다.

    @Test
    public void dtoByExpressionUtils() {

        QMember subQuery = new QMember("subQuery");

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

 

 

4. @QueryProjection

    @Test
    public void dtoByQueryProjection() {
        List<MemberDto> result = queryFactory
                .select(
                        new QMemberDto(member.username, member.age))
                .from(member)
                .fetch();
    }

@QueryProjection은 constructor()와 유사하다고 생각할 수 있지만 컴파일 시점에서 오류를 잡을 수 있는 반면, constructor()는 런타임에서 오류를 발견하게 됩니다. 그러나 @QueryProjection을 사용하면 순수한 DTO 클래스가 QueryDSL에 의존하게 되는 단점이 있어 DTO가 controller, service, repository 등 여러 계층에서 사용될 경우 다른 계층도 QueryDSL에 의존하게 되는 문제가 발생합니다.

 

 

 

참고자료

https://jojoldu.tistory.com/379

 

[Querydsl] 서브쿼리 사용하기

안녕하세요! 이번 시간에는 Querydsl에서의 Subquery 기본 가이드를 진행합니다. 개인적으로 ORM을 사용하며, 객체지향적으로 엔티티가 구성되어있으면 서브쿼리가 필요한 일은 거의 없다고 생각하

jojoldu.tistory.com

https://jong-bae.tistory.com/63

 

[QueryDSL] Projections, @QueryProjection 을 사용하여 DTO로 반환하기

엔티티가 연관관계없이 특정 컬럼들만 조인해서 뽑아와야 할때가 있다. 이때 엔티티에 값을 담아서 리턴할 수 없어서 DTO에 반환해야 하는데 Projections 를 이용하면 보기좋게 코드를 작성할 수 있

jong-bae.tistory.com

https://green-bin.tistory.com/24

 

JPA - Querydsl를 사용해 DTO 받는 방법

프로젝트를 진행하면서 조회한 도메인을 Mapstruct 라이브러리를 사용해 DTO로 매핑했었다. 하지만 점점 비즈니스 로직이 복잡해면서 매핑을 위한 코드도 같이 복잡해지다보니 도메인을 거치지

green-bin.tistory.com