본문 바로가기

카테고리 없음

JPA-애니 리스트 조회하기

간단하게 JPA를 공부해보고 바로 적용해보는데 에러가 발생했다.

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'animationRepository' defined in hello.repository.AnimationRepository defined in @EnableJpaRepositories declared on JpaConfig: Could not create query for public abstract java.util.List hello.repository.AnimationRepository.findAnimations(); Reason: Validation failed for query for method public abstract java.util.List hello.repository.AnimationRepository.findAnimations()

AnimationRepository 인터페이스의 findAnimations() 메서드에 대한 쿼리 생성이 실패했다는데

나는 아무리봐도 모르겠다 맞게 쓴 거 같은데..

import hello.dto.animation.GetAniListDTO;
import hello.entity.animation.Animation;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import java.util.List;

public interface AnimationRepository extends JpaRepository<Animation, Long> {
// 애니 전체 리스트 조회
@Query("SELECT new hello.dto.animation.GetAniListDTO(a.id, a.imagePath, " +
        "COALESCE(SUM(r.likeCount), 0), COALESCE(AVG(r.score), 0)) " +
        "FROM Animation a LEFT JOIN a.reviews r " +
        "WHERE a.imagePath IS NOT NULL AND a.existReview = TRUE " +
        "GROUP BY a.id, a.imagePath")

List<GetAniListDTO> findAnimations();

 

간단하게 모든 정보를 다불러오게해도 에러가 발생.
밑으로 좀 더 내려보니 또 다른 에러있었는데 이게 문제인거 같았다.

Caused by: org.hibernate.query.SemanticException: Missing constructor for type 'GetAniListDTO' [SELECT new hello.dto.animation.GetAniListDTO(a.id, a.imagePath, COALESCE(SUM(r.likeCount), 0), COALESCE(AVG(r.score), 0)) FROM Animation a LEFT JOIN a.reviews r WHERE a.imagePath IS NOT NULL AND a.existReview = TRUE GROUP BY a.id]
at org.hibernate.query.hql.internal.SemanticQueryBuilder.visitInstantiation(SemanticQueryBuilder.java:1506)
at org.hibernate.query.hql.internal.SemanticQueryBuilder.visitInstantiation(SemanticQueryBuilder.java:275)
at org.hibernate.grammars.hql.HqlParser$InstantiationContext.accept(HqlParser.java:4029)
at org.hibernate.query.hql.internal.SemanticQueryBuilder.visitSelectableNode(SemanticQueryBuilder.java:1453)
at org.hibernate.query.hql.internal.SemanticQueryBuilder.visitSelection(SemanticQueryBuilder.java:1407)
at org.hibernate.query.hql.internal.SemanticQueryBuilder.visitSelectClause(SemanticQueryBuilder.java:1400)
at org.hibernate.query.hql.internal.SemanticQueryBuilder.visitQuery(SemanticQueryBuilder.java:1249)
at org.hibernate.query.hql.internal.SemanticQueryBuilder.visitQuerySpecExpression(SemanticQueryBuilder.java:1035)
at org.hibernate.query.hql.internal.SemanticQueryBuilder.visitQuerySpecExpression(SemanticQueryBuilder.java:275)
at org.hibernate.grammars.hql.HqlParser$QuerySpecExpressionContext.accept(HqlParser.java:2132)
at org.hibernate.query.hql.internal.SemanticQueryBuilder.visitSimpleQueryGroup(SemanticQueryBuilder.java:1020)
at org.hibernate.query.hql.internal.SemanticQueryBuilder.visitSimpleQueryGroup(SemanticQueryBuilder.java:275)
at org.hibernate.grammars.hql.HqlParser$SimpleQueryGroupContext.accept(HqlParser.java:2003)
at org.hibernate.query.hql.internal.SemanticQueryBuilder.visitSelectStatement(SemanticQueryBuilder.java:490)
at org.hibernate.query.hql.internal.SemanticQueryBuilder.visitStatement(SemanticQueryBuilder.java:449)
at org.hibernate.query.hql.internal.SemanticQueryBuilder.buildSemanticModel(SemanticQueryBuilder.java:322)
at org.hibernate.query.hql.internal.StandardHqlTranslator.translate(StandardHqlTranslator.java:71)
at org.hibernate.query.internal.QueryInterpretationCacheStandardImpl.createHqlInterpretation(QueryInterpretationCacheStandardImpl.java:145)
at org.hibernate.query.internal.QueryInterpretationCacheStandardImpl.resolveHqlInterpretation(QueryInterpretationCacheStandardImpl.java:132)
at org.hibernate.internal.AbstractSharedSessionContract.interpretHql(AbstractSharedSessionContract.java:802)
at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:852)
... 85 common frames omitted

 

원인은 JPQL 쿼리를 실행할 때 DTO에 정의된 생성자와 쿼리에서 호출된 생성자의 매개변수 타입이 일치하지 않는 것이 문제였다.

package hello.dto.animation;

import lombok.Data;

@Data
public class GetAniListDTO {

    private long id;

    private String imagePath;

    private int likeCount;

    private double score;

    public GetAniListDTO(long id, String imagePath, int likeCount, double score) {
        this.id = id;
        this.imagePath = imagePath;
        this.likeCount = likeCount;
        this.score = score;
    }

}

 

likeCount와 score 필드는 int와 double 타입으로 선언하였는데,

쿼리에서 SUM(r.likeCount)와 AVG(r.score)는 Long과 Double 타입만을 반환할 수 있다.

하지만 DTO 생성자는 int와 double을 받으려해서 타입 불일치로 인해 생성자를 찾지 못하는 에러가 발생한 것이였다.

[ 해결 방법 ]

타입 일치

  • DTO의 필드 타입을 Long과 Double로 변경하여 쿼리에서 반환되는 타입과 DTO 생성자의 파라미터 타입을 맞춰주었다.
package hello.dto.animation;

import lombok.Data;

@Data
public class GetAniListDTO {

    private Long id;
    private String imagePath;
    private Long likeCount;
    private Double averageScore;

    public GetAniListDTO(Long id, String imagePath, Long likeCount, Double averageScore) {
        this.id = id;
        this.imagePath = imagePath;
        this.likeCount = likeCount;
        this.averageScore = averageScore;
    }
}

 

 

해결!