2017-09-14 74 views
0

我想用接口的find方法,而不是在實現中使用。JPA:通過接口而不是實現來尋找

,這裏說的是我的代碼:

public Goods findGoods(Long goodsId) { 
    return this.jpaApi.withTransaction(()->{ 
     Goods goods = null; 
     try{ 
      EntityManager em = this.jpaApi.em(); 
      Query query = em.createQuery("select g from Goods g where id=:id", Goods.class); 
      query.setParameter("id", goodsId); 
      goods = (Goods) query.getSingleResult(); 
     }catch (Exception e) { 
      // TODO: handle exception 
      e.printStackTrace(); 
     } 
     return goods; 
    }); 
} 

我的實體:

@Entity(name = "Goods") 
@Table(name = "GOODS") 
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) 
public class GoodsImp implements Goods, Serializable { 
.. 
} 

我的接口:

@JsonTypeInfo(include = JsonTypeInfo.As.PROPERTY, property = "type", 
use = Id.NAME, defaultImpl = GoodsImp.class, visible = true) 
@JsonSubTypes({ @Type(value = ProductImp.class, name = "product"), 
       @Type(value = ServiceImp.class, name = "service") }) 
@ImplementedBy(GoodsImp.class) 
public interface Goods { 
.. 
} 

錯誤:

java.lang.IllegalArgumentException: Unable to locate persister: interfaces.Goods at org.hibernate.internal.SessionImpl.find(SessionImpl.java:3422) at org.hibernate.internal.SessionImpl.find(SessionImpl.java:3365) at repository.JPAGoodsRepository.lambda$deleteGoods$2(JPAGoodsRepository.java:58) at play.db.jpa.DefaultJPAApi.lambda$withTransaction$3(DefaultJPAApi.java:197)

我的疑問是爲什麼我有這個問題,如果當我使用查詢語句與接口工作正常。

這工作:

@Override 
    public Collection<Goods> getAllGoods() { 
     return this.jpaApi.withTransaction(() -> { 
      Collection<Goods> goods = null; 
      try { 
       EntityManager em = this.jpaApi.em(); 
       Query query = em.createQuery("Select g from Goods g", Goods.class); 
       goods = query.getResultList(); 
      } catch (Exception e) { 
       // TODO: handle exception 
       e.printStackTrace(); 
      } 
      return goods; 
     }); 

    } 
+0

JPA API不認爲接口值得持久性處理。 DataNucleus JPA確實允許那個JPQL,但是不知道其他任何人都這麼做,並且你無論如何都會參與供應商擴展 – DN1

+0

因此,我只能在JPQL中使用接口,但不能在.find方法中使用? – Aleyango

+0

正如我所說,JPA不考慮接口,所以如果堅持規範並且只有1個我知道的供應商支持它們,您就不能使用它們,但是您沒有使用它。 – DN1

回答

1

EntityManager方法createQuery您使用的聲明爲:

<T> TypedQuery<T> createQuery(String qlString, Class<T> resultClass) 

原因Class<T> resultClass參數來推斷的T類型,使你可以這樣寫:

List<Goods> listOfGoods = em.createQuery("select g from Goods g where id=:id", Goods.class).getResultList(); 

沒有得到編譯器警告。 resultClass參數是肯定不是告訴entityManager您正在查詢哪種實體類型。這是通過查詢的select g from Goods g部分來完成的,順便說一句,Goods是實體GoodsImpl的別名(您可以使用@Entity(name = "Bads")註釋GoodsImpl實體,並且select b from Bads b也可以工作)。

現在,如果我理解正確,請問爲什麼em.find(entityClass, primaryKey)呼叫失敗,Goods.class用於entityClass。你可以找到EntityManager在javadoc的答案,其中find據說拋出:

IllegalArgumentException - if the first argument does not denote an entity type

的實體類型,unsuprisingly,一類註解爲@Entity

如果你問爲什麼這是它的實現方式,那麼答案很簡單。一個接口可以由幾個類來實現。假設您有多個實體類實現Goods,每個實體類都有自己的表和自己的ID。在這些不同的實體中不會有重疊的id。 JPA應該如何知道你希望獲得哪些實體?

+0

很好的答案,這是我想要的。非常感謝。所以我的選擇是,使用帶有別名的TypedQuery或使用實體本身的find方法。非常感謝。 – Aleyango