나는 이것에 대한 몇 가지 해결책을 발견했다.
매핑 된 엔터티 사용 (JPA 2.0)
JPA 2.0을 사용하면 기본 조회를 POJO에 맵핑 할 수 없으며 엔티티로만 수행 할 수 있습니다.
예를 들어 :
Query query = em.createNativeQuery("SELECT name,age FROM jedi_table", Jedi.class);
@SuppressWarnings("unchecked")
List<Jedi> items = (List<Jedi>) query.getResultList();
그러나이 경우, Jedi
는 맵핑 된 엔티티 클래스 여야합니다.
여기서 확인되지 않은 경고를 피하기위한 대안은 명명 된 기본 쿼리를 사용하는 것입니다. 따라서 엔티티에서 기본 쿼리를 선언하면
@NamedNativeQuery(
name="jedisQry",
query = "SELECT name,age FROM jedis_table",
resultClass = Jedi.class)
그런 다음 간단히 할 수 있습니다.
TypedQuery<Jedi> query = em.createNamedQuery("jedisQry", Jedi.class);
List<Jedi> items = query.getResultList();
이것은 더 안전하지만 여전히 매핑 된 엔터티를 사용하도록 제한되어 있습니다.
수동 매핑
내가 JPA 2.1이 도착하기 전에 약간의 실험을 한 솔루션은 약간의 리플렉션을 사용하여 POJO 생성자에 대한 매핑을 수행하고있었습니다.
public static <T> T map(Class<T> type, Object[] tuple){
List<Class<?>> tupleTypes = new ArrayList<>();
for(Object field : tuple){
tupleTypes.add(field.getClass());
}
try {
Constructor<T> ctor = type.getConstructor(tupleTypes.toArray(new Class<?>[tuple.length]));
return ctor.newInstance(tuple);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
이 메소드는 기본적으로 튜플 배열 (네이티브 쿼리에 의해 리턴 됨)을 가져와 동일한 수의 필드와 동일한 유형의 생성자를 찾아 제공된 POJO 클래스에 맵핑합니다.
그런 다음 다음과 같은 편리한 방법을 사용할 수 있습니다.
public static <T> List<T> map(Class<T> type, List<Object[]> records){
List<T> result = new LinkedList<>();
for(Object[] record : records){
result.add(map(type, record));
}
return result;
}
public static <T> List<T> getResultList(Query query, Class<T> type){
@SuppressWarnings("unchecked")
List<Object[]> records = query.getResultList();
return map(type, records);
}
그리고 우리는이 기술을 다음과 같이 간단하게 사용할 수 있습니다 :
Query query = em.createNativeQuery("SELECT name,age FROM jedis_table");
List<Jedi> jedis = getResultList(query, Jedi.class);
@SqlResultSetMapping을 사용한 JPA 2.1
JPA 2.1이 출시되면 @SqlResultSetMapping 주석을 사용하여 문제를 해결할 수 있습니다.
엔티티 어딘가에 결과 세트 맵핑을 선언해야합니다.
@SqlResultSetMapping(name="JediResult", classes = {
@ConstructorResult(targetClass = Jedi.class,
columns = {@ColumnResult(name="name"), @ColumnResult(name="age")})
})
그리고 우리는 단순히 :
Query query = em.createNativeQuery("SELECT name,age FROM jedis_table", "JediResult");
@SuppressWarnings("unchecked")
List<Jedi> samples = query.getResultList();
물론이 경우 Jedi
매핑 된 엔터티 일 필요는 없습니다. 일반적인 POJO 일 수 있습니다.
XML 매핑 사용
나는 @SqlResultSetMapping
엔티티 에이 모든 것을 침범하는 것을 발견 한 사람들 중 하나이며 특히 엔티티 내의 명명 된 쿼리의 정의를 싫어하므로 META-INF/orm.xml
파일 에서이 모든 것을 수행 합니다.
<named-native-query name="GetAllJedi" result-set-mapping="JediMapping">
<query>SELECT name,age FROM jedi_table</query>
</named-native-query>
<sql-result-set-mapping name="JediMapping">
<constructor-result target-class="org.answer.model.Jedi">
<column name="name" class="java.lang.String"/>
<column name="age" class="java.lang.Integer"/>
</constructor-result>
</sql-result-set-mapping>
그리고 그것들은 내가 아는 모든 솔루션입니다. 마지막 두 가지는 JPA 2.1을 사용할 수있는 이상적인 방법입니다.