20220627-TIL

만년 쭈글이 개발자·2022년 6월 27일
0

TIL

목록 보기
1/13

집계하지 못하는 고통

1:N 관계에서 N에 해당되는 금액값들의 집계를 해서 dto를 뽑아내야 했다.
특별히 어려울 것 없는 그냥 집계함수(sum) 쓰면 되는 쿼리..
우리회사는 jpa를쓰고 있어서 쿼리를 queryDSL로 짠다.

금액 컬럼은 보통 BigDecimal을 쓰지만 나는 BigDecimal을 한번 더 감싸서 화폐정보가 담긴 Class(편의상 MyMoney로 지칭하겠음)를 사용했다. 이 클래스는 대충 아래와 같다

public class MyMoney implements Serializable, Comparable<MyMoney>, Immutable {
	private BigDecimal amount;
    private Currency currency;
}

문제는 그러다보니...QClass가 만들어질때 NumberPath로 만들어지지 않았다는 점이다. 그냥 Comparable만 구현하다보니 Q파일이 만들어질때도 당연하게
ComparablePath로 만들어져 버린다..

public final ComparablePath<MyMoney> moneyAmt = ...
public final NumberPath<Long> money1 = ...

그러나 집계 함수는 NumberExpression 클래스에만 존재함 ^^
결국 entity의 금액필드들을 다 BigDecimal로 바꿔야 할 것 같다ㅜㅜ
머리가 나쁘면 몸이 고생이지

오늘의 교훈 : 집계를 할거같은 항목은 entity 짤 때 미리 생각해서 Number를 상속하는 객체로 하거나 걍 BigDecimal을 쓰자

시간날때 queryDSL 라이브러리 좀 봐야겠다...그냥 막 쓰니까 이런 일이 생기는 것 같기도 해서 반성...

++ 추가

사수님이 ComparablePath를 NumberExpression으로 바꾸는 방법을 알려주셨다. 물론 이 경우는 MyMoney가 내부값으로 BigDecimal을 가지고 있기 때문에 가능하다.

Expressions.numberOperation

public static NumberExpression<BigDecimal> sum(ComparablePath<MyMoney> money) {
        return Expressions.numberOperation(BigDecimal.class, Ops.AggOps.SUM_AGG, money);
    }

Expression.class


    /**
     * Create a new Operation expression
     *
     * @param type type of expression
     * @param operator operator
     * @param args operation arguments
     * @return operation expression
     */
    public static <T extends Number & Comparable<?>> NumberOperation<T> numberOperation(Class<? extends T> type,
            Operator operator, Expression<?>... args) {
        return new NumberOperation<T>(type, operator, args);
    }

이 건의 추가적인 문제...
쿼리는 집계로 나가야 하기 때문에 BigDecimal, 그리고 다시 반환되는 tuple 에서는 본래의 MyMoney 타입으로 들어오는 문제가 있어서 tuple로 직접 받아야 하고 Projections.field() 등을 이용한 dto 매핑을 할 수가 없다...
dto의 컬럼이 BigDecimald 일 때는 받을 때 MyMoney이기 때문에 형변환 에러가 나고, dto 를 MyMoney로 해두면 중간에 집계처리 BigDecimal 처리할 때 에러가 난다. 그래서 뭉뚱그려서 처리하는 tuple 인 경우에만 안 터지는 듯...

profile
오늘의 나는 내일의 나보다 젊지

0개의 댓글