본문 바로가기

Spring Boot/Spring Data JPA

QueryDSL) From 절 SubQuery를 쓰고싶어

querydsl은 from절 서브쿼리를 지원하지 않아 답답한 적이 많았는데 다음 방법으로 from절 서브쿼리를 사용해보자.

 

하이버네이트 @Subselect를 이용해서 서브 쿼리로 사용할 엔티티에 가상 view 처럼 사용하는 것이다. 그렇게 되면 native query로 작성하는 것처럼 사용이 가능하다. 아래는 @Subselect 사용예제이다

 

 

subquery용 entity생성

@Entity
@Subselect(
        "select * " +
        "from VERSION " +
        "where VERSION_ID in " +
        "( " +
            "select max(SW_RELS_NUM) " +
            "from VERSION " +
            "where CRT_DT in " +
            "( " +
                "select max(CRT_DT) " +
                "from VERSION " +
                "group by APP_ID " +
            ") " +
            "group by APP_ID " +
        ")"
)
@Immutable
@Synchronize("VERSION")
public class SubQuery {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "VERSION_ID", nullable = false)
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "APP_ID")
    private App app;

    @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "VERSION_FILE")
    private File file;
}

(주의할 점은 @Column 에서 정의한 컬럼 명과 @SubSelect 에서 정의한 컬럼이 일치해야 정상적으로 동작한다)

 

어노테이션

  • @Immutable, @Subselect, @Synchronize는 하이버네이트 전용 어노테이션으로 쿼리 결과를 @Entity로 매핑
    @Subselect는 조회 쿼리를 값으로 갖는다.
  • @Immutable은 변경 내용을 방지하기 위해 사용한다. (해당 엔티티의 필드/프로퍼티가 변경되어도 반영 무시)
  • @Synchronize는 @Subselect가 만든 view에 접근하기 위한 테이블을 정의

 (출처: https://hesh1232.tistory.com/155 )

 

 

 

reposiotry querydsl

 

위에서 생성한 엔티티를 Q클래스로 생성 후 사용하고자 하는 from 절에 넣어주면

위에서 정의된 쿼리를 from절에서 사용할 수 있다.

// 서브쿼리 선언
QSubQuery subQuery = new QSubQuery("subQuery");

...
AppResponse result = jpaQueryFactory.select(
                    new QAppResponse(
                            app.id,
                            new QVersionResponse(
                                    version.id,
                                    new QFileResponse(
                                            file.id,
                                            file.flExtn,
                                            file.flPath,
                                    ).skipNulls()
                            )
                    )
                )
                .from(app)
                .leftJoin(subQuery).on(app.id.eq(subQuery.app.id))
                .leftJoin(subQuery.file, file)
                .where(keywordNull(keywordName, keyword))
                .where(eqAll(type))
                .fetch();
        
...

 

 

결국 from 서브쿼리는 사용하지 않았다.

'Spring Boot > Spring Data JPA' 카테고리의 다른 글

querydsl 에서 case문 사용하기  (0) 2024.01.07
QueryDsl) BooleanExpression  (1) 2023.12.17
queryDsl 정리 및 예제  (1) 2023.12.03
JPA) JPA Auditing으로 자동화  (0) 2023.12.01
JPA) Entity Graph 로 N+1 이슈 해결하기  (0) 2023.10.29