在JPA 2.0 中咱們可使用entityManager.createNativeQuery()來執行原生的SQL語句。 但當咱們查詢結果沒有對應實體類時,query.getResultList()返回的是一個List<Object[]>。也就是說每行的數據被做爲一個對象數組返回。
java
常見的用法是這樣的:sql
public void testNativeQuery(){ Query query = entityManager.createNativeQuery("select id, name, age from t_user"); List rows = query.getResultList(); for (Object row : rows) { Object[] cells = (Object[]) row; System.out.println("id = " + cells[0]); System.out.println("name = " + cells[1]); System.out.println("age = " + cells[2]); } }
這樣用會使代碼很是不容易讓人理解, 究竟下標爲0的元素究竟是什麼, 不去數查詢語句是不知道的,並且一旦查詢語句被調整,Java代碼也要一塊兒調整。這時候咱們想若是返回的是Map的話,用起來會清晰的多。
惋惜的是JPA的API中並無提供這樣的設置。其實不少JPA的底層實現都是支持返回Map對象的。例如:
EclipseLink的query.setHint(QueryHints.RESULT_TYPE, ResultType.Map);
Hibernate的.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
因此,若是咱們想要返回Map而且肯定底層用的是某一種JPA的實現時咱們能夠退而求其次, 犧牲跨實現的特性來知足咱們的需求:數組
public void testNativeQuery(){ Query query = entityManager.createNativeQuery("select id, name, age from t_user"); query.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP); List rows = query.getResultList(); for (Object obj : rows) { Map row = (Map) obj; System.out.println("id = " + row.get("ID")); System.out.println("name = " + row.get("NAME")); System.out.println("age = " + row.get("AGE")); } }
或者
public List<Map> findMapBySql(String sqlStr) {
Session session = getEntityManager().unwrap(Session.class);
return session.createSQLQuery(sqlStr).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list();
}
這裏須要注意的是, 用Map確定要比用Object數組來的效率低。因此你要看性能降低是否在可接受範圍內。再就是在個人Hibernate 4.2.x的環境下,不管你原生SQL中寫的是大寫字母仍是小寫字母,返回的字段名都是大寫的。固然你能夠經過自定義ResultTransformer的形式對字段名進行必定的處理, 甚至是返回本身須要的POJO。session
還有一種更簡單的辦法:性能
Query query = em.createNativeQuery(sql,java.util.Map.class);
這樣就能夠直接返回Map格式的結果集了。spa