記錄一個jpa
多表查詢返回自定義對象異常

JPA 多表查詢映射異常

博客索引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 &gt; 25) AND (order_item = i.id)",
 *    "OrderResults");
 *    
 *    &#064;SqlResultSetMapping(name="OrderResults", 
 *        entities={ 
 *            &#064;EntityResult(entityClass=com.acme.Order.class, fields={
 *                &#064;FieldResult(name="id", column="order_id"),
 *                &#064;FieldResult(name="quantity", column="order_quantity"), 
 *                &#064;FieldResult(name="item", column="order_item")})},
 *        columns={
 *            &#064;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

相關文章
相關標籤/搜索