코딩 자율학습단/학습 일지

[DAY 14] 댓글 CRUD : InvalidDataAccessApiUsageException 에러

young604 2024. 8. 18. 23:18
728x90

Many-To-One

게시글과 댓글은 1:N, 즉 다대일 관계이다. 게시글 하나당 n개의 댓글이 달리기 때문이다.

그리하여 댓글 CRUD를 위한 엔티티를 생성할때, @manytoone 어노테이션을 선언해주고, 외래키 매핑을 해주어야 한다.

또한 댓글은 CRUD 뿐만 아니라 페이지별로 정렬하여 나타내야하기때문에 CrudRepository를 상속받는 것이 아닌 JpaRepository를 상속 받아 ListCrudRepository와 ListPagingAndSortingRepository 기능을 사용할 것이다.

외래키 매핑

@JoinColumn(name="외래키_이름")

댓글 엔티티는 게시글 엔티티의 id를 외래키로 사용한다. 그러므로 name은 article_id가 된다

특정 게시글의 모든 댓글 조회

해당 메서드에서 조회를 하려면 DB 쿼리문이 들어가야한다. 쿼리를 적는 방법은 2가지이다.

1. @Query 어노테이션 이용 (해당 메서드에 바로 적음)

@Query(value = "쿼리", nativeQuery = true

@Query 어노테이션은 JSQL을 사용하기 때문에, 일반 SQL 쿼리문을 그대로 쓰러면 꼭 nativeQuery=true 옵션을 적어줘야 한다. 또한 where 절에서 매개변수 앞에는 꼭 콜론(:)을 붙여 줘야 메서드에서 넘긴 매개변수와 매칭이 된다.

@Query(value = "SELECT * FROM comment WHERE article_id = :articleId", nativeQuery = true)

2. orm.xml 파일 이용 (resource 파일에 새 파일 만들어야함)

XML로 쿼리를 작성하기 위해서는 꼭 해당 위치에 해당 이름으로 파일을 생성해야 스프링에서 인식할 수 있다.

XML에서는 <entity-mappings> 태그 안에 <named-native-query> 와 <query> 태그를 사용하여 쿼리를 작성한다.

<?xml version="1.0" encoding="utf-8" ?>
<entity-mappings xmlns="https://jakarta.ee/xml/ns/persistence/orm"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence/orm
                 https://jakarta.ee/xml/ns/persistence/orm/orm_3_0.xsd"
                 version="3.0">
    <named-native-query
            name="Comment.findByNickname"
            result-class="com.example.firstproject.entity.Comment">
        <query>
            <![CDATA[
                SELECT * FROM comment WHERE nickname = :nickname
            ]]>
        </query>
    </named-native-query>
</entity-mappings>

<named-native-query> 태그의 name 속성에는 쿼리를 수행하는 대상 엔티티.메서드 이름,

result-class 속성에는 쿼리가 반환하는 타입의 전체 패키지 경로를 적는다

<query> 태그에는 실제 수행할 쿼리를 <![CDATA[ .. ]]> 구문 안에 작성해야 한다.

CDATA는 Character DATA로, 파싱되지 은 문자 데이터를 쓸 때 사용한다.

테스트 코드 작성

댓글이 올바르게 조회되는지 테스트할 코드를 작성한다.

테스트 케이스를 여러개 작성하고 싶을 때에는 테스트 메소드 안에서 중괄호로 구분하면 된다.

또한 테스트 메소드 이름을 바꾸지 않고도 결과 터미널에 이름을 바꿔서 출력하고 싶을때, @DisplayName 어노테이션을 메소드 앞에 달아주면 이름을 바꿀 수 있다.

Trouble Shooting

문제 상황

테스트 코드를 실행하니 다음 에러가 발생함.

org.springframework.dao.InvalidDataAccessApiUsageException: For queries with named parameters you need to provide names for method parameters; Use @Param for query method parameters, or when on Java 8+ use the javac flag -parameters

JpaRepository를 이용하는 CommentRepository에서 조회하려니 발생한 오류로, java 8 이상에서는 @Param 어노테이션을 사용하거나 -parameters flag를 사용해야한다는 것.

해결 방법

java 8에서는 리플렉션을 통해 메소드의 매개변수 이름에 접근할 수 있어 해당 어노테이션이 생략 가능한데, 이를 생략하기 위해서는 compiler flag `-parameters` 를 사용해야 한다.

그래서 넣어줬다.

근데 안되길래(...) 결국 @Param 어노테이션을 코드에 넣어줬다.

 

@Param : 매개변수의 name을 통해 메서드의 매개변수를 쿼리에 바인드 시키는 어노테이션

해당 메서드의 매개변수 앞에 @Param 어노테이션을 추가하여 이름을 명시해주어야 한다.

public interface CommentRepository extends JpaRepository<Comment, Long> {
    // 특정 게시글의 모든 댓글 조회
    @Query(value = "SELECT * FROM comment WHERE article_id = :articleId",
            nativeQuery = true) // value 속성에 실행하려는 쿼리 작성
    List<Comment> findByArticleId(@Param("articleId") Long articleId);
    // 특정 닉네임의 모든 댓글 조회
    List<Comment> findByNickname(@Param("nickname") String nickname);
}

잘된다,, 허허. 앞으로 JPARepository를 상속 받으면 @Param 어노테이션을 잊지 말것...

728x90