博客索引java
最近用JPA多表查詢出現一個問題javax.persistence.PersistenceException: org.hibernate.MappingException: Unknown SqlResultSetMapping [Record]
。因爲使用多表鏈接查詢想返回一個自定義的對象。sql
環境: JPA 2.2.8bash
還原場景:表A,Bapp
@Entity
public Class A{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name ;
private String age;
...省略get set
}
@Entity
public Class B{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Long a_id;//對應A表的id
private String like ;
private String hate;
...省略get set
}
複製代碼
返回自定義對象Record
:各包含A,B部分屬性框架
public Class Record{
private Long a_id;
private Long b_id;
private String name ;
private String like;
...省略get set
}
複製代碼
DAO以下:post
@PersistenceContext
private EntityManager em;
String SQL ="select a.id as a_id,a.name as name , b.id as b_id, b.like as like from A a,B b where a.id =b.a_id;";
List<Record> adminLists = em.createNativeQuery(SQL).getResultList();
複製代碼
而後問題出現了,javax.persistence.PersistenceException: org.hibernate.MappingException: Unknown SqlResultSetMapping [Record]
。 這應該是沒法將查詢結果轉換爲自定義的Record
。 因而第一種方法就是返回一個Object對象或者Object[] DAO修改成:ui
List<Object[]> adminLists = em.createNativeQuery(SQL).getResultList();
複製代碼
而後手動遍歷,去給自定義的類賦值。spa
第二個思路: 我想一個框架應該會考慮到這些問題,而後經過一番搜索,stackoverflow上面有相關問題 發現有個註解@SqlResultSetMapping
能解決問題,查看該註解源碼:hibernate
/**
* Specifies the mapping of the result of a native SQL query or stored
* procedure.
*
* <pre>
* Example:
*
* Query q = em.createNativeQuery(
* "SELECT o.id AS order_id, " +
* "o.quantity AS order_quantity, " +
* "o.item AS order_item, " +
* "i.name AS item_name, " +
* "FROM Order o, Item i " +
* "WHERE (order_quantity > 25) AND (order_item = i.id)",
* "OrderResults");
*
* @SqlResultSetMapping(name="OrderResults",
* entities={
* @EntityResult(entityClass=com.acme.Order.class, fields={
* @FieldResult(name="id", column="order_id"),
* @FieldResult(name="quantity", column="order_quantity"),
* @FieldResult(name="item", column="order_item")})},
* columns={
* @ColumnResult(name="item_name")}
* )
* </pre>
*
* @see Query
* @see StoredProcedureQuery
* @see NamedNativeQuery
* @see NamedStoredProcedureQuery
*
* @since 1.0
*/
@Repeatable(SqlResultSetMappings.class)
@Target({TYPE})
@Retention(RUNTIME)
public @interface SqlResultSetMapping {
···
}
複製代碼
發現註釋上寫着指定的映射原生SQL查詢結果或者儲存過程,也就是能夠將查詢出來的結果按照對應的規則進行映射。註釋正好有個demo。code
不賣關子了,直接上解決流程: 修改類Record
;
@SqlResultSetMapping(name = "findRecords",
entities = {
@EntityResult(entityClass = com.xxx.Record.class, fields = {
@FieldResult(name = "a_id", column = "a_id"),
@FieldResult(name = "b_id", column = "b_id"),
@FieldResult(name = "name", column = "name"),
@FieldResult(name = "like", column = "like")
})}
)
@Entity
public Class Record{
@Id
private Long a_id;
private Long b_id;
private String name ;
private String like;
...省略get set
}
複製代碼
DAO修改以下:
String SQL ="select a.id as a_id,a.name as name , b.id as b_id, b.like as like from A a,B b where a.id =b.a_id;";
List<Record> adminLists = em.createNativeQuery(SQL,"findRecords").getResultList();
複製代碼
至於原理,暫時尚未時間去研究。下次有時間補上。 可是我猜想:查詢的結果是一個Object[]類型,而後經過@SqlResultSetMapping
註解定義的返回值類型,把結果給自定義類型賦值。
若是還有疑問,請留言或者經過郵箱聯繫我creazycoder@sina.com