인프런 커뮤니티 질문&답변

rudgkrk11님의 프로필 이미지
rudgkrk11

작성한 질문수

실전! 스프링 데이터 JPA

Projections

class projection 중 오류발

해결된 질문

작성

·

328

0


[질문 템플릿]
1. 강의 내용과 관련된 질문인가요? (예/아니오)
2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)
3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)

[질문 내용]
[질문 템플릿]
1. 강의 내용과 관련된 질문인가요? 예
2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예
3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예


[질문 내용]
Class projection 중
class MemberClassProjections(
private final String memberName;

public MemberClassProjections
(String memberName) {
this.memberName = memberName;
}


public String getMemberName() {
return memberName;
}

)

class로 projection을 하면

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'memberRepository' defined in jpaShop.shop.domain.member.repository.MemberRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration: Could not create query for public abstract java.util.List jpaShop.shop.domain.member.repository.MemberRepository.findMemberClassProjectionByMemberName(java.lang.String); Reason: Failed to create query for method public abstract java.util.List jpaShop.shop.domain.member.repository.MemberRepository.findMemberClassProjectionByMemberName(java.lang.String); Source must not be null or empty

메서드 생성 오류가 표출되는데

public record MemberClassProjections(String memberName) {
}

record로 만들면 오류없이 잘 실행이 됩니다.
이유가 뭘까요..

 

답변 4

1

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. rudgkrk11님

도움을 드리고 싶지만 질문 내용만으로는 답변을 드리기 어렵습니다.

실제 동작하는 전체 프로젝트를 ZIP파일로 압축해서 구글 드라이브로 공유해서 링크를 남겨주세요.

구글 드라이브 업로드 방법은 다음을 참고해주세요.

https://bit.ly/3fX6ygx

 

주의: 업로드시 링크에 있는 권한 문제 꼭 확인해주세요

추가로 다음 내용도 코멘트 부탁드립니다.

1. 문제 영역을 실행할 수 있는 방법

2. 문제가 어떻게 나타나는지에 대한 상세한 설명

링크: 공식 서포터즈

링크: 자주하는 질문

감사합니다.

0

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. rudgkrk11님

다음을 참고해서 코드를 고쳐주세요.

기존 코드

package jpaShop.shop.domain.member.projection;

import org.springframework.beans.factory.annotation.Value;

public interface MemberProjections {
    @Value("#{target.memberName + ' ' + target.address.city}")
    String getMemberName();

    String getCity();
}

 

변경 코드

package jpaShop.shop.domain.member.projection;

import org.springframework.beans.factory.annotation.Value;

public interface MemberProjections {
    @Value("#{target.memberName}")
    String getMemberName();

    @Value("#{target.address.city}")
    String getCity();
}

감사합니다.

rudgkrk11님의 프로필 이미지
rudgkrk11
질문자

아...class projection이 아니라 open projection에서 오류가 나고있었군요...감사합니다

0

rudgkrk11님의 프로필 이미지
rudgkrk11
질문자

https://drive.google.com/file/d/109KqnEg1n5ljaT59s1BWGJ5ZHg7o411m/view?usp=sharing

1. main/java/jpashop/shop/domain/member/projection/MemberClassProjection
test/java/jpashop/shop/member/memberControllerTest 57번 라인으로 테스트 진행했습니다!

오류
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'memberRepository' defined in jpaShop.shop.domain.member.repository.MemberRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration: Could not create query for public abstract java.util.List jpaShop.shop.domain.member.repository.MemberRepository.findMemberClassProjectionByMemberName(java.lang.String); Reason: Failed to create query for method public abstract java.util.List jpaShop.shop.domain.member.repository.MemberRepository.findMemberClassProjectionByMemberName(java.lang.String); Source must not be null or empty

2.class projection 진행 중 MemberClassProjection를 class로 projection 시 위의 오류가 발생하고
record type으로 바꿔서projection 진행 시 오류가 나지 않습니다..

0

안녕하세요, 인프런 AI 인턴입니다.

rudgkrk11님의 질문에 대한 답변입니다.

해당 문제는 class 기반의 projection과 record 기반의 projection의 차이에서 기인합니다. Spring Data JPA에서는 값 타입 DTO(value type DTOs)를 projection으로 사용할 때 Java Records를 이용하는 것을 권장합니다. Records는 모든 필드가 private final이며, equals(...), hashCode(), toString() 메서드가 자동으로 생성됩니다. 또한, 사용자가 정의한 생성자를 통하여 필요한 필드만을 포함시킬 수 있으며, Spring Data JPA는 이를 통해 쿼리 최적화를 할 수 있습니다. 반면에, class를 사용할 경우 추가적인 설정이 필요할 수 있으며, 복잡성이 증가합니다.

문제 발생의 근본적인 이유는 class 기반의 projection을 사용할 때, JPQL의 생성자 표현식(constructor expression)을 사용해야 하며, 이러한 방식이 native query와는 호환되지 않기 때문입니다. 이와 달리, record를 사용할 경우 그러한 복잡성이 줄어들며, Spring Data JPA에서는 이를 더 효율적으로 처리할 수 있습니다.

따라서, class를 사용하여 projection을 정의할 때는 해당 class가 적절한 생성자를 가지고 있고, 이 생성자가 JPQL이나 @Query 어노테이션에서 사용될 수 있도록 명시되어 있어야 합니다. 하지만, record는 이러한 과정을 자동으로 처리하기에 별다른 추가 작업 없이도 projection으로 사용할 수 있습니다.

자세한 내용은 Spring Data JPA 공식 문서의 Class-based Projections 부분을 참고해 주시기 바랍니다.
- Spring Data JPA 도큐먼테이션 - Class-based Projections (DTOs)

이로 인해 record를 사용할 때보다 class를 사용할 때 발생하는 문제가 해결되지 않는 것을 볼 수 있습니다. 간결하고 효율적인 코드를 작성하기 위해서는 가능한 경우 Java Records 사용을 고려하는 것이 좋습니다.

rudgkrk11님의 프로필 이미지
rudgkrk11

작성한 질문수

질문하기