//imports, etc.
@Entity
@Table(name = "TSTRANS")
@SqlResultSetMappings(
{
@SqlResultSetMapping(name = TS_TRANS_EMP_STAT,
classes = {
@ConstructorResult(
targetClass = EmpStat.class,
columns = {
@ColumnResult(name = "EMPID", type = Long.class),
@ColumnResult(name = "CODE", type = String.class),
@ColumnResult(name = "TOTALCOUNT", type = Integer.class)
}
)
})
}
)
@NamedNativeQueries({
@NamedNativeQuery(name = "TsTrans.getStat", query = "select * from SP_TASK_STATS_EMP (:in_empid, :in_gidstr, :in_onlytodo)", resultSetMapping = TS_TRANS_EMP_STAT)
})
public class TsTrans extends TsTransCommon {
public static final String TSTRANS_BADGE = "TSTRANS_BADGE";
private static final long serialVersionUID = -3391028108003625153L;
public static final String TS_TRANS_EMP_STAT = "TsTrans.empStat";
public static final String TS_TRANS_SCHEDULE_STAT = "TsTrans.getScheduleStat";
public static final String TS_TRANS_FOLLOWUP = "TS_TRANS_FOLLOWUP";
}
C'est l'entité.
// imports, etc.
public class EmpStat extends BaseStat {
private static final long serialVersionUID = -4410895509438727581L;
private Long mEmpid;
public EmpStat(Long aEmpid, String aCode, Integer aTotalcount) {
super(aCode, aTotalcount);
mEmpid = aEmpid;
}
public Long getEmpid() {
return mEmpid;
}
public void setEmpid(Long aEmpid) {
mEmpid = aEmpid;
}
}
C'est le type de retour pojo non-entité, namedquery.
// imports, etc.
@Repository
public interface TsTransRepository extends TsTransCommonRepository<TsTrans> {
List<EmpStat> getStat(@Param("in_empid") Long aEmpid, @Param("in_gidstr") String aGidstr, @Param("in_onlytodo") Boolean aOnlytodo);
}
C'est la classe du référentiel.
J'utilise ce namednativequeries pour renvoyer des pojos non-entités à partir de procédures stockées. Cela fonctionne sans exception depuis Spring Boot 1.5.9. Et sur Spring Boot 2.0.0.M7. Après la migration vers la version 2.0.0.RELEASE, l'exception suivante a commencé à se produire.
org.hibernate.HibernateException: Got different size of tuples and aliases
at org.hibernate.jpa.spi.NativeQueryTupleTransformer$NativeTupleImpl.<init>(NativeQueryTupleTransformer.Java:68) ~[hibernate-core-5.2.14.Final.jar:5.2.14.Final]
at org.hibernate.jpa.spi.NativeQueryTupleTransformer.transformTuple(NativeQueryTupleTransformer.Java:28) ~[hibernate-core-5.2.14.Final.jar:5.2.14.Final]
at org.hibernate.hql.internal.HolderInstantiator.instantiate(HolderInstantiator.Java:85) ~[hibernate-core-5.2.14.Final.jar:5.2.14.Final]
at org.hibernate.loader.custom.CustomLoader.getResultList(CustomLoader.Java:430) ~[hibernate-core-5.2.14.Final.jar:5.2.14.Final]
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.Java:2507) ~[hibernate-core-5.2.14.Final.jar:5.2.14.Final]
at org.hibernate.loader.Loader.list(Loader.Java:2502) ~[hibernate-core-5.2.14.Final.jar:5.2.14.Final]
at org.hibernate.loader.custom.CustomLoader.list(CustomLoader.Java:335) ~[hibernate-core-5.2.14.Final.jar:5.2.14.Final]
at org.hibernate.internal.SessionImpl.listCustomQuery(SessionImpl.Java:2161) ~[hibernate-core-5.2.14.Final.jar:5.2.14.Final]
at org.hibernate.internal.AbstractSharedSessionContract.list(AbstractSharedSessionContract.Java:1016) ~[hibernate-core-5.2.14.Final.jar:5.2.14.Final]
at org.hibernate.query.internal.NativeQueryImpl.doList(NativeQueryImpl.Java:152) ~[hibernate-core-5.2.14.Final.jar:5.2.14.Final]
at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.Java:1414) ~[hibernate-core-5.2.14.Final.jar:5.2.14.Final]
at org.hibernate.query.Query.getResultList(Query.Java:146) ~[hibernate-core-5.2.14.Final.jar:5.2.14.Final]
at org.springframework.data.jpa.repository.query.JpaQueryExecution$CollectionExecution.doExecute(JpaQueryExecution.Java:129) ~[spring-data-jpa-2.0.5.RELEASE.jar:2.0.5.RELEASE]
at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.Java:91) ~[spring-data-jpa-2.0.5.RELEASE.jar:2.0.5.RELEASE]
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.Java:136) ~[spring-data-jpa-2.0.5.RELEASE.jar:2.0.5.RELEASE]
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.Java:125) ~[spring-data-jpa-2.0.5.RELEASE.jar:2.0.5.RELEASE]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.Java:590) ~[spring-data-commons-2.0.5.RELEASE.jar:2.0.5.RELEASE]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.Java:578) ~[spring-data-commons-2.0.5.RELEASE.jar:2.0.5.RELEASE]
Ai-je oublié quelque chose pendant la migration?
Dans jpa 2.1, en mettant l'annotation @Query(nativeQuery = true)
sur la méthode d'interface du référentiel, corrige le problème . Référence:
Changez votre SqlResultSetMappings
en
@SqlResultSetMappings({
@SqlResultSetMapping(name = TS_TRANS_EMP_STAT,
columns = {
@ColumnResult(name = "EMPID", type = Long.class),
@ColumnResult(name = "CODE", type = String.class),
@ColumnResult(name = "TOTALCOUNT", type = Integer.class)
})
}
et changez EmpStat
de la classe normale à l'interface:
public interface EmpStat {
Long getEMPID();
String getCODE();
Integer getTOTALCOUNT();
}
J'ai trouvé une solution supplémentaire: vous pouvez simplement supprimer le générique de List dans getStat ():
@Repository
public interface TsTransRepository extends TsTransCommonRepository<TsTrans> {
List getStat(@Param("in_empid") Long aEmpid, @Param("in_gidstr") String aGidstr, @Param("in_onlytodo") Boolean aOnlytodo);
}
Il existe plusieurs approches pour y remédier, principalement une combinaison de différentes fonctionnalités de données jpa et spring. J'ai fait des recherches et les ai ajoutées pour publier https://jira.spring.io/browse/DATAJPA-1280 . Pour trouver ce que vous pourriez faire, veuillez regarder ce projet https://github.com/EugeneNik/spring-data-datajpa-1280-example et exécuter des tests pour voir quelles approches fonctionnent correctement à l’heure actuelle. Notez qu’il n’existe actuellement aucun moyen de migrer sans modification du code, mais la solution la plus simple est d’ajouter une déclaration de projection de classe à votre méthode de référentiel. En le définissant, vous ne devez pas changer tous les mappages, mais les invocations de référentiels doivent également être modifiées. C'est juste une autre façon de résoudre votre problème:
@Repository
public interface TsTransRepository extends TsTransCommonRepository<TsTrans>
{
<T> List<T> getStat(@Param("in_empid") Long aEmpid,
@Param("in_gidstr") String aGidstr, @Param("in_onlytodo") Boolean aOnlytodo, Class<T> beanProjection);
}
Je pense que ceci est le rapport de problème dans Spring Data JPA: https://jira.spring.io/browse/DATAJPA-1280
Pour contourner le problème, vous pouvez rétrograder vers le train de versions Spring Data Kay-SR4 (SR5 est la version la plus récente et utilisée dans Spring Boot 2.0.0). Il suffit d'ajouter:
<spring-data-releasetrain.version>Kay-SR4</spring-data-releasetrain.version>
dans la section <properties>
de votre pom.xml.
Comme d'autres l'ont noté, il s'agissait d'un bogue introduit dans Spring Boot 2.0.0 et signalé dans DATAJPA-1280 .
Il a été corrigé et publié dans Spring Boot 2.0.3.