NativeQueryでconstructor-resultを使ってSELECTしてみる
TweetPosted on Sunday Jan 26, 2014 at 02:35PM in Technology
NativeQueryで複数のエンティティを1度にSELECTしてみるの続きです。JPA2.1のNativeQueryの新機能constructor-resultを使ってSELECTしてみます。
constructor-resultはJPQLのNEW句のようなものです。エンティティを拾ってくるクエリでなく、レポート的なのを出すクエリの場合とかに使うとキャストが要らなくなるので便利っぽいです。
環境
- Hibernate 4.3.0.Final
- WildFly8.0.0.CR1
- Oracle JDK7u51
- postgresql-9.3-1100.jdbc41.jar
- PostgreSQL 9.2.4
何をするか
エンティティと関連の構造は前回と同じです。
今回はDeptエンティティのdeptNameと、EmployeeのカウントをSELECTしてみます。
準備
配置図

図中で選択されている資源を作成または編集します。
- orm.xmlにNamedNativeQuery “findDeptNameAndEmployeeCount” とResultSetMapping “deptNameAndEmployeeCountResult” を追加します
- テストクラスConstructorResultSelectTestを作ります
- DTOクラスDeptNameAndEmployeeCountを作ります
- テストデータは前回のを流用します
DeptNameAndEmployeeCount.java
package org.arquillian.example;
public class DeptNameAndEmployeeCount {
private String deptName;
private Number employeeCount;
public DeptNameAndEmployeeCount(String deptName, Number employeeCount) {
super();
this.deptName = deptName;
this.employeeCount = employeeCount;
}
@Override
public String toString() {
return "DeptNameAndEmployeeCount [deptName=" + deptName + ", employeeCount=" + employeeCount + "]";
}
}
orm.xml
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings version="2.1"
xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence/orm http://xmlns.jcp.org/xml/ns/persistence/orm_2_1.xsd">
<named-native-query name="findDeptNameAndEmployeeCount" result-set-mapping="deptNameAndEmployeeCountResult">
<query><![CDATA[
SELECT
dep.deptName,
COUNT(dep.deptName) AS employeeCount
FROM
Dept AS dep,
Employee AS emp
WHERE
dep.id = emp.dept_id
GROUP BY
dep.deptName
]]></query>
</named-native-query>
<sql-result-set-mapping name="deptNameAndEmployeeCountResult">
<constructor-result target-class="org.arquillian.example.DeptNameAndEmployeeCount">
<column name="deptName" class="java.lang.String" />
<column name="employeeCount" class="java.lang.Number" />
</constructor-result>
</sql-result-set-mapping>
</entity-mappings>
- column要素のclass属性は省略可みたい(少なくともHibernate4.3.1では動いた)
- ただcolumn要素自体は省略不可っぽい
ConstructorResultSelectTest.java
package org.arquillian.example;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.transaction.Transactional;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.arquillian.persistence.UsingDataSet;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.EmptyAsset;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(Arquillian.class)
public class ConstructorResultSelectTest {
@Deployment
public static Archive<?> createDeployment() {
Archive<?> a = ShrinkWrap.create(WebArchive.class, "test.war")
.addPackage(Employee.class.getPackage())
.addAsResource("test-persistence.xml", "META-INF/persistence.xml")
.addAsResource("META-INF/orm.xml", "META-INF/orm.xml")
.addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml")
.addAsWebInfResource("jbossas-ds.xml");
return a;
}
@PersistenceContext
EntityManager em;
@Test
@Transactional
@UsingDataSet({"datasets/relativeSelect/dept.yml", "datasets/relativeSelect/employees.yml"})
public void select() throws Exception {
dumpEntityList(em.createNamedQuery("findDeptNameAndEmployeeCount").getResultList());
}
protected void dumpEntityList(List<?> list){
for(Object o : list){
System.out.println(o);
}
}
}
実行結果
14:42:45,278 INFO [stdout] (pool-2-thread-17) Hibernate: SELECT dep.deptName, COUNT(dep.deptName) AS employeeCount FROM Dept AS dep, Employee AS emp WHERE dep.id = emp.dept_id GROUP BY dep.deptName 14:42:45,281 INFO [stdout] (pool-2-thread-17) DeptNameAndEmployeeCount [deptName=Legal, employeeCount=1] 14:42:45,282 INFO [stdout] (pool-2-thread-17) DeptNameAndEmployeeCount [deptName=Sales, employeeCount=2]
キャストが要らないのがいいですね。
続き
NativeQueryで複数のエンティティを同時にSELECTしつつconstructor-resultを使ってみる
参考文献
Tags: jpa