ネイティブSQLの結果をPOJOにマップしようとしています。これが設定です。春を使用しています。
<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>
これが私のクラスです
@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
ここで私はそれをどのように呼んでいますか
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();
しかし、それはラインになると
List<CourseCompletion> courseCompletionList = query.getResultList();
私はそのエラーを受け取ります
Could not locate appropriate constructor on class : mypackage.CourseCompletion
これが私が試しているクエリです
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
このエラーが発生するのはなぜですか?
ありがとう
この例外は、JPAがネイティブクエリのデータベースから返された列の型を変更しないために発生します。このため、型が一致しません。あなたのケースでどの列がこの問題の原因であるかはわかりませんが(これは使用するDBMSによって異なります)、結果セットにBigInteger
の代わりにInteger
がscore列。 100%確実にするには、ConstructorResultColumnProcessor.resolveConstructor(Class targetClass, List<Type> types)
にブレークポイントを追加して調査します。不一致を見つけたら、マッピングクラスのフィールドタイプを変更します。
別の解決策は、@SqlResultSetMapping
をまったく使用しないことです。 CourseCompletion
クラスは管理対象エンティティであるため、ネイティブクエリを直接そのエンティティにマップできるはずです。詳細は この質問 を参照してください。
ConstructorResultColumnProcessor.resolveConstructor
にブレークポイントを追加するとうまくいきました。私のクエリにはrowNum
の選択があり、BigDecimal
タイプとしてマップされています。 BigInteger
を使用してコンストラクターを作成していました。