작성
·
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 인턴입니다.
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