SPRING FRAMEWORK

Querydsl에서 DTO를 사용하는 방법

Ambitions 2020. 3. 4. 12:09

개발을 하고 있는데, 서로 연관 관계가 없는 테이블간에 데이터를 가져와야 할 일이 있었다, 

각 Entity들에 @OneToMany나 @ManyToOne 어노테이션을 이용해 데이터를 가져오는 방법도 고려해보았으나, 

위 방법은 제일 간단한 방법이였지만, 서로 연관관계도 없는 Entity에 @ManyToOne나 @OneToMany을

이용하는 건 코드품질상, 관리적 측면에서 올바르지 않다고 판단되었다, 따라서 querydsl을 이용해 데이터를 가져오기로 했으나, 막상 코드를짜서 실행해보니, 맨 앞에 선언되어있는 엔티티의 데이터만 가져오고 조인된 나머지 데이터들을 가져오지 못하는 문제가 발생했다.

 

DTO를 이용해 데이터를 받아야겠다는 생각까지는 도달했으나, 당최 JPA서는 DTO를 어떻게 사용해야하는지 감이 안잡혔다;; 기존 spring JDBC나 mybatis에서는 쉽게 사용했던 것 같은데, JPA에서는 엔티티라는 클래스가 있기 떄문에 더욱 더 작업을 어렵게했다.

그래서 찬찬히 찾아보니... DTO 클래스를 만드는 것 까지는 동일하나, 생성자에 하나의 @QueryProjection 어노테이션을 사용해주면 된다는 것이다, 이걸 코드로 표현해보자면 다음과 같다. (이 코드는 예시를 들기위해 작성한 내용이다)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Getter
public class TestDTO { // 두개의 테이블에서 4개의 데이터만 가져온다고 가정
    
    private String name;
    
    private String hobby;
    
    private Integer age;
    
    private BigDecimal salary
    
    @QueryProjection
    public TestDTO(String name, String hobby, Integer age, BigDecimal salary) { // 생성자
    
        this.name = name;
        this.hobby = hobby;
        this.age = age;
        this.salary = salray
        
    }
 
}
 
cs

DTO 클래스는 위와 같이 써주면 되고, queryDsl 쿼리는 다음과 같이 써주면 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*
* QuerydslRepositorySupport를 상속받고 있음
* ...중략
*  통상적으로 직원과 회사테이블의 경우 연관관계가 존재하는 구조이나, 설명을 위해 작성함.
*/ 
 
@Override
public List<TestDTO> getDatas() { 
    
    JPAQueryFactory queryFactory = new JPAQueryFactory(getEntityManager());
    QMember member = QMemeber.qmemebr;
    QEmployment employment = QEmployment.qemployment;
    
    return queryFactory.select(Projections.constructor(TestDTO.class
    memebr.name, memebr.hobby, memeber.age, employment.salray)) 
    .from(member).innerJoin(employment).on(member.name.eq(employment.name))
    .fetch();
    
}
 
cs

주의할점은 생성자의 순서와 select문 순서가 동일해야한다는 점이다.

위와같이 방식으로 사용했더니 문제없이 데이터를 문제없이 가져오는 것을 확인할 수 있었다.

mybatis를 사용할 떄와는 다르게 JPA를 사용하니 이런 문제가 발생하는 것 같다, 아니 애초에 테이블 설계가 잘되어있으면 이런 고민을 할 필요가 없지 않았을까? 라는 생각도 든다. 여러모로 JPA는 참 어렵다.