πŸ“— JPA

JPA μ§‘κ³„ν•¨μˆ˜ sum 은 long 을 λ°˜ν™˜ν•œλ‹€.

GroovyArea 2023. 7. 26. 23:28

졜근 λŒ€λŸ‰μ˜ 데이터듀을 μ§‘κ³„ν•˜μ—¬ μ‘°νšŒν•˜λŠ” API ν”„λ‘œμ νŠΈλ₯Ό μ§„ν–‰ 쀑에,

Spring Data JPA 와 Querydsl 을 μ΄μš©ν•˜μ—¬ 쿼리λ₯Ό μž‘μ„±ν•˜κ³  μžˆμ—ˆλ‹€.

 

였늘, sum 집계 ν•¨μˆ˜ λ•Œλ¬Έμ—, java object 둜 맀핑이 μ•ˆλ˜λŠ” λ¬Έμ œκ°€ μžˆμ—ˆλŠ”λ°,

κ·Έ μ΄μœ μ™€ 해결과정을 μ„€λͺ…해보겠닀.

 

기쑴 쿼리

@Query(
        """
            select
            new service.dto.PaymentTotalSumDTO(
                sum(sub.totalAmount) as totalAmount,
                sum(sub.discount) as discount,
                sum(sub.usedPoint) as usedPoint
                )
            from
            (select
                tpd.totalAmount as totalAmount,
                tpd.discount as discount,
                tpd.usedPoint as usedPoint,
            from TransactionPaymentDetail tpd
            where tpd.sid = :sid
            group by
            tpd.pid,
            tpd.totalAmount,
            tpd.discount,
            tpd.usedPoint) sub
        """
    )
    fun findTotalSumBySid(
        sid: String
    ): PaymentTotalSumDTO?
    
    data class PaymentTotalSumDTO(
    val totalAmount: BigDecimal = BigDecimal.ZERO,
    val discount: BigDecimal = BigDecimal.ZERO,
    val usedPoint: BigDecimal = BigDecimal.ZERO,
    )

JPQL 둜 groupby ν•˜μ—¬ 얻은 μ„œλΈŒμΏΌλ¦¬μ—μ„œ 각 μ»¬λŸΌλ³„λ‘œ sum 을 λ•Œλ € DTO 둜 μ‘°νšŒν•˜λŠ” ν•¨μˆ˜μ΄λ‹€.

ν•΄λ‹Ή query λŠ” μ΄λŸ¬ν•œ μ—λŸ¬λ₯Ό λ°œμƒμ‹œν‚€λ©°, μ‹€νŒ¨ν•œλ‹€.

Caused by: java.lang.IllegalArgumentException: org.hibernate.QueryException: Function argument [SqmBasicValuedSimplePath(<<derived>>(sub).totalAmount)] of type [org.hibernate.query.derived.AnonymousTupleSqmPathSource@59282e4a] at specified position [1] in call arguments was not typed as an allowable function return type
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:141)
at org.hibernate.query.spi.AbstractSelectionQuery.list(AbstractSelectionQuery.java:374)
at org.hibernate.query.sq m.internal.QuerySqmImpl.list(QuerySqmImpl.java:1073) 
at org.hibernate.query.spi.AbstractSelectionQuery.getSingleResult(AbstractSelectionQuery.java:457)
at org.hibernate.query.sqm.internal.QuerySqmImpl.getSingleResult(QuerySqmImpl.java:1103)

 

무엇이 λ¬Έμ œμ˜€μ„κΉŒ?

- ν•˜μ΄λ²„λ„€μ΄νŠΈμ˜ μ§‘κ³„ν•¨μˆ˜ sum 은 long νƒ€μž…μ„ λ°˜ν™˜ν•œλ‹€.

BigDecimal νƒ€μž…κ³Ό Long νƒ€μž…μ΄ μΌμΉ˜ν•˜μ§€ μ•Šμ•„, object 둜 맀핑이 λ˜μ§€ μ•ŠλŠ” 것이닀.

 

μ–΄λ–»κ²Œ ν•΄μ•Ό ν• κΉŒ?

@Query(
        """
            select
            new service.dto.PaymentTotalSumDTO(
                sum(cast(sub.totalAmount as bigdecimal)) as ta,
				sum(cast(sub.discount as bigdecimal)) as discount,
				sum(cast(sub.usedPoint as bigdecimal)) as usedPoint
                )
            from
            (select
                tpd.totalAmount as totalAmount,
                tpd.discount as discount,
                tpd.usedPoint as usedPoint,
            from TransactionPaymentDetail tpd
            where tpd.sid = :sid
            group by
            tpd.pid,
            tpd.totalAmount,
            tpd.discount,
            tpd.usedPoint) sub
        """
    )
    fun findTotalSumBySid(
        sid: String
    ): PaymentTotalSumDTO?

- cast ν•¨μˆ˜λ₯Ό μ΄μš©ν•˜μ—¬ bigdecimal νƒ€μž…μœΌλ‘œ μΊμŠ€νŒ… ν•΄μ£Όμ—ˆλ‹€.

μ„œλΈŒ 쿼리인 sub λŠ” μ‹€ν–‰μ‹œμ μ— entity 에 λͺ…μ‹œλœ νƒ€μž…λŒ€λ‘œ bigdecimal νƒ€μž…μ„ λ°˜ν™˜ν•˜μ§€λ§Œ, 

sub λ₯Ό μ΄μš©ν•˜μ—¬ select ν•˜λŠ” κ΅¬κ°„μ—μ„œ ν•˜μ΄λ²„λ„€μ΄νŠΈλŠ” type 적용이 λ˜μ§€ μ•Šμ•„λ²„λ¦°λ‹€.

DB λ‹¨μ—μ„œ ν•œλ²ˆμ— μΏΌλ¦¬ν•˜λŠ” 것이 μ•„λ‹Œ, μ• ν”Œλ¦¬μΌ€μ΄μ…˜ λ©”λͺ¨λ¦¬μ—μ„œ long 을 λ°˜ν™˜ν•˜λŠ” sum ν•¨μˆ˜κ°€ μ‹€ν–‰λ˜κΈ° λ•Œλ¬Έμ΄λ‹€.

 

그럼 μ •μƒμ μœΌλ‘œ 쿼리가 μ‹€ν–‰λ˜λŠ” 것을 μ•Œ 수 μžˆλ‹€.

 

According to the JPA spec 4.5.8

The Java type that is contained in the result of a query using an aggregate function is as follows:

• COUNT returns Long.

• MAX, MIN return the type of the state field to which they are applied.

• AVG returns Double.

• SUM returns Long when applied to state fields of integral types (other than BigInteger); Double when applied to state fields of floating point types; BigInteger when applied to state fields of type BigInteger; and BigDecimal when applied to state fields of type BigDecimal.

 

μ°Έμ‘° :

https://stackoverflow.com/questions/61954687/jpa-sum-returns-long

λ°˜μ‘ν˜•