인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

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

Sj Choi님의 프로필 이미지

작성한 질문수

실전! 스프링 데이터 JPA

네이티브 쿼리

UsernameOnlyDto 타입 type mismatch 오류

작성

·

39

0


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

[질문 내용]
여기에 질문 내용을 남겨주세요.

UsernameOnly 인터페이스 타입과 지네릭스 타입으로 결과는 문제 없이 동작하지만

UsernameOnlyDto 타입으로 결과 값을 받으려고 findProjectionsByUsername를 호출하면

type mismatch 오류가 생깁니다.


Specified result type [study.datajpa.dto.UsernameOnlyDto] did not match Query selection type [study.datajpa.entity.Member] - multiple selections: use Tuple or array


List<UsernameOnlyDto> result = memberRepository.findProjectionsByUsername("m1");
package study.datajpa.dto;

public class UsernameOnlyDto {
    private final String username;

    public UsernameOnlyDto(String username) {
        this.username = username;
    }

    public String getUsername() {
        return username;
    }
}
// List<UsernameOnly> findProjectionsByUsername(@Param("username") String username);

 List<UsernameOnlyDto> findProjectionsByUsername(@Param("username") String username);

<T> List<T> findProjectionsByUsername(@Param("username") String username, Class<T> type);

 

org.springframework.orm.jpa.JpaSystemException: Specified result type [study.datajpa.dto.UsernameOnlyDto] did not match Query selection type [study.datajpa.entity.Member] - multiple selections: use Tuple or array

at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:341)

at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:241)

at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:560)

at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)

at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:343)

at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:160)

at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)

at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:136)

at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)

at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:223)

at jdk.proxy2/jdk.proxy2.$Proxy149.findProjectionsByUsername(Unknown Source)

at study.datajpa.repository.MemberRepositoryTest.projections(MemberRepositoryTest.java:403)

at java.base/java.lang.reflect.Method.invoke(Method.java:568)

at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)

at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)

Suppressed: org.springframework.transaction.UnexpectedRollbackException: Transaction silently rolled back because it has been marked as rollback-only

at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:804)

at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:758)

at org.springframework.test.context.transaction.TransactionContext.endTransaction(TransactionContext.java:135)

at org.springframework.test.context.transaction.TransactionalTestExecutionListener.afterTestMethod(TransactionalTestExecutionListener.java:272)

at org.springframework.test.context.TestContextManager.afterTestMethod(TestContextManager.java:488)

at org.springframework.test.context.junit.jupiter.SpringExtension.afterEach(SpringExtension.java:275)

... 2 more

Caused by: org.hibernate.query.QueryTypeMismatchException: Specified result type [study.datajpa.dto.UsernameOnlyDto] did not match Query selection type [study.datajpa.entity.Member] - multiple selections: use Tuple or array

at org.hibernate.query.sqm.internal.SqmUtil.throwQueryTypeMismatchException(SqmUtil.java:1272)

at org.hibernate.query.sqm.internal.SqmUtil.verifyResultType(SqmUtil.java:1209)

at org.hibernate.query.sqm.internal.SqmUtil.verifySelectionType(SqmUtil.java:1159)

at org.hibernate.query.sqm.internal.SqmUtil.verifySingularSelectionType(SqmUtil.java:1114)

at org.hibernate.query.sqm.internal.SqmUtil.checkQueryReturnType(SqmUtil.java:1088)

at org.hibernate.query.sqm.internal.SqmUtil.checkQueryReturnType(SqmUtil.java:1049)

at org.hibernate.query.sqm.internal.SqmUtil.validateQueryReturnType(SqmUtil.java:1040)

at org.hibernate.query.sqm.tree.select.SqmSelectStatement.validateResultType(SqmSelectStatement.java:153)

at org.hibernate.query.sqm.internal.QuerySqmImpl.<init>(QuerySqmImpl.java:240)

at org.hibernate.internal.AbstractSharedSessionContract.createCriteriaQuery(AbstractSharedSessionContract.java:1483)

at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:1443)

at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:143)

at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)

at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

at java.base/java.lang.reflect.Method.invoke(Method.java:568)

at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:320)

at jdk.proxy2/jdk.proxy2.$Proxy136.createQuery(Unknown Source)

답변 1

0

인프런 AI 인턴님의 프로필 이미지

안녕하세요, 인프런 AI 인턴입니다.
Sj Choi님, DTO 타입과 관련된 오류에 대해 설명드리겠습니다.

지금 UsernameOnlyDto를 사용하여 결과 값을 받으려 하실 때 발생하는 type mismatch 오류는 스프링 데이터 JPA에서 지정한 반환 타입과 쿼리의 실제 선택 타입이 일치하지 않을 때 발생할 수 있습니다.

예를 들어, UsernameOnlyDto를 사용해 결과 값을 기대하려면 JPQL 쿼리에서 명시적으로 해당 DTO 객체를 생성해야 합니다. 예를 들어, JPQL 쿼리를 다음과 같이 작성해야 합니다:

@Query("SELECT new study.datajpa.dto.UsernameOnlyDto(m.username) FROM Member m WHERE m.username = :username")
List<UsernameOnlyDto> findProjectionsByUsername(@Param("username") String username);

위와 같이 쿼리를 작성하면 UsernameOnlyDto의 생성자를 통해서만 필드가 채워지도록 보장할 수 있어야 하며, 쿼리에서 정확히 매핑되는 필드를 new 구문과 함께 사용해야 제대로 동작합니다.

이럴 경우, UsernameOnlyDto는 생성자로 필드를 주입받기 때문에 DTO 객체가 올바르게 생성됩니다. 문제를 해결하기 위해 SQL 쿼리를 생성할 때 반환 타입에 맞는 정확한 프로젝션을 사용해 보세요.

추가적으로 JPQL 쿼리나 네이티브 쿼리를 사용하는 방법에 따라 각각 다른 방식으로 사용해야 할 수 있습니다. JPQL을 사용할 때는 프로젝션 방식이 JPA Criteria 또는 JPQL을 이용해 정확하게 설정되어야 오류가 발생하지 않습니다.
자세한 내용은 다음 문서를 참고해주세요:
Spring Data JPA - Projections

Sj Choi님의 프로필 이미지

작성한 질문수

질문하기