본문 바로가기
Spring

[QueryDSL] String to Int, Varchar to Number (castToNum)

by 노력남자 2021. 10. 18.
반응형

가끔 가다가 DB 설계가 이상하게 되어 있어서 Number 타입이었어야 하는 컬럼이 Varchar로 되어 있는 경우가 있다.

 

이런 경우 음 그냥 String을 Int로 바꿔서 쿼리하면 되는 거 아니야? 라고 생각이 드는데 QueryDSL에선 그게 불가능하다.

 

해결 방법은 castToNum을 사용하면 된다. 아래 예제를 봐보자.

 

해결 방법

 

Comment의 seq는 원래 Int가 정상인데 잘못된 설계로 인해 String으로 설계가 되어있다고 가정한다. (DB: MySQL)

 

@NoArgsConstructor
@AllArgsConstructor
@Entity
public class Comment {

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

    private String seq; // Int가 정상

    @OneToOne
    private Board board;
}

 

seq가 2보다 큰 Comment를 가져오는 경우에 QComment의 seq를 보면 StringPath로 되어 있어서 goe나 loe 같은 메소드를 사용할 수 없다.

 

 

이런 경우엔 NumberExpression으로 변경해주는 castToNum을 사용하면 된다.

 

@Override
public List<Comment> findBySeqGreaterThanEqual(int seq) {
    return queryFactory
            .selectFrom(comment)
            .where(comment.seq.castToNum(Integer.class).goe(seq)) // castToNum 사용
            .fetch();
}

 

아래와 같이 테스트를 돌려서 쿼리를 확인해보면 cast 함수를 사용해서 쿼리를 던지는 걸 볼 수 있다.

 

@Test
void findByOrderGreaterThanEqual() {

    for (int i=0; i<3; i++) {
        commentRepository.save(new Comment(null, String.valueOf(i), null));
    }

    List<Comment> comments = commentRepository.findBySeqGreaterThanEqual(2);

    assertThat(comments.size()).isEqualTo(1);
}

= select
	comment0_.id as id1_1_,
	comment0_.board_id as board_id3_1_,
	comment0_.seq as seq2_1_ 
  from
	comment comment0_ 
  where
	cast(comment0_.seq as signed)>=?

 

Int 대신 Long이 필요한 경우 Long.class를 사용하면 된다.

반응형

댓글