J'essaie de mapper le résultat SQL natif à mon POJO. Voici la configuration. J'utilise le printemps.
<bean id="ls360Emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" >
<property name="dataSource" ref="ls360DataSource" />
<property name="jpaVendorAdapter" ref="vendorAdaptor" />
<property name="packagesToScan" value="abc.xyz"/>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>
<prop key="hibernate.max_fetch_depth">3</prop>
<prop key="hibernate.jdbc.fetch_size">50</prop>
<prop key="hibernate.jdbc.batch_size">10</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
Voici ma classe
@SqlResultSetMapping(
name="courseCompletionMapping",
classes = {
@ConstructorResult(targetClass = CourseCompletion.class,
columns={
@ColumnResult(name = "StoreId", type = String.class),
@ColumnResult(name = "ProductId", type = String.class),
@ColumnResult(name = "UserName", type = String.class),
@ColumnResult(name = "Score", type = Integer.class),
@ColumnResult(name = "CompletionDate", type = Date.class)
}
)
}
)
@Entity
public class CourseCompletion {
private String storeId;
@Id
private String productId;
private String userName;
private int score;
private Date completionDate;
public CourseCompletion() {
}
public CourseCompletion(String storeId, String productId, String userName, int score, Date completionDate) {
this.storeId = storeId;
this.productId = productId;
this.userName = userName;
this.score = score;
this.completionDate = completionDate;
}
// getters and setters
Voici comment je l'appelle
Properties coursePropertiesFile = SpringUtil.loadPropertiesFileFromClassPath("course.properties");
String queryString = coursePropertiesFile.getProperty("course.completion.sql");
long distributorId = 1;
String fromDate = "2009-09-22 00:00:00";
String toDate = "2014-04-11 23:59:59";
Query query = em.createNativeQuery(queryString, "courseCompletionMapping");
//Query query = em.createNamedQuery("findAllEmployeeDetails");
query.setParameter("distributorId", distributorId);
query.setParameter("fromDate", fromDate);
query.setParameter("toDate", toDate);
@SuppressWarnings("unchecked")
List<CourseCompletion> courseCompletionList = query.getResultList();
Mais quand il s'agit de ligne
List<CourseCompletion> courseCompletionList = query.getResultList();
Je reçois une erreur
Could not locate appropriate constructor on class : mypackage.CourseCompletion
Voici la requête que j'essaie
select d.DISTRIBUTORCODE AS StoreId, u.USERGUID AS ProductId, u.UserName,
lcs.HIGHESTPOSTTESTSCORE AS Score, lcs.CompletionDate
from VU360User u
inner join learner l on u.ID = l.VU360USER_ID
inner join LEARNERENROLLMENT le on le.LEARNER_ID = l.ID
inner join LEARNERCOURSESTATISTICS lcs on lcs.LEARNERENROLLMENT_ID = le.ID
inner join customer c on c.ID = l.CUSTOMER_ID
inner join DISTRIBUTOR d on d.ID = c.DISTRIBUTOR_ID
where d.ID = :distributorId
and lcs.COMPLETIONDATE is not null
and (lcs.COMPLETIONDATE between :fromDate and :toDate)
and lcs.COMPLETED = 1
Pourquoi je reçois cette erreur?
Merci
Cette exception se produit car JPA ne modifie pas les types de colonnes renvoyés par la base de données pour les requêtes natives. Pour cette raison, vous avez une incompatibilité de type. Je ne sais pas quelle colonne provoque ce problème dans votre cas (cela dépend du SGBD que vous utilisez), mais je soupçonne que vous avez BigInteger
dans le jeu de résultats au lieu de Integer
pour colonne de score . Pour être sûr à 100%, ajoutez un point d'arrêt à ConstructorResultColumnProcessor.resolveConstructor(Class targetClass, List<Type> types)
et examinez. Après avoir trouvé une incompatibilité, modifiez le type de champ dans votre classe de mappage.
Une autre solution sera de ne pas utiliser @SqlResultSetMapping
du tout. Comme votre classe CourseCompletion
est une entité gérée, vous devriez pouvoir lui mapper directement la requête native. Voir cette question pour plus d'informations.
Ajout d'un point d'arrêt au ConstructorResultColumnProcessor.resolveConstructor
a fonctionné pour moi. Ma requête avait une sélection rowNum
et elle est mappée en tant que type BigDecimal
. J'avais le constructeur avec un BigInteger
.