2013-07-26 17 views
0

我正面臨JOIN FETCH和EAGER關係的問題。JPA ArgumentException在EAGER共享關係上執行JOIN FETCH時發生錯誤oneToOne

我有以下實體關係:

實體A擴展抽象的實體E.

摘要實體E具有與實體下的oneToOne雙向關係與預先抓取類型

實體A與實體B.

實體B一對多關係延伸抽象實體E(所以具有以C oneToOne關係太)

實體C具有相反的關係,以抽象的實體È

雖然執行一個簡單的命名查詢如

SELECT a FROM A a WHERE a.key = :key 

其中參數'key'是字符串類型,那麼我沒有問題。從檢索到的實體A訪問子實體B按照其假定的那樣執行子請求。

但是,如果我添加一個連接抓取到我的namedQuery:

SELECT a FROM A a JOIN FETCH a.entitiesB WHERE a.key = :key 

我得到下面的錯誤堆棧跟蹤:

javax.ejb.EJBTransactionRolledbackException: The transaction has been marked rollback only because the bean encountered a non-application exception :javax.ejb.EJBTransactionRolledbackException : The transaction has been marked rollback only because the bean encountered a non-application exception :org.apache.openjpa.persistence.ArgumentException : The specified parameter of type "class org.apache.openjpa.util.LongId" is not a valid query parameter. 
at org.apache.openejb.core.ivm.BaseEjbProxyHandler.convertException(BaseEjbProxyHandler.java:345) 
at org.apache.openejb.core.ivm.BaseEjbProxyHandler.invoke(BaseEjbProxyHandler.java:283) 
... 
Caused by: <openjpa-2.2.0-r422266:1244990 nonfatal user error> org.apache.openjpa.persistence.ArgumentException: The specified parameter of type "class org.apache.openjpa.util.LongId" is not a valid query parameter. 
FailedObject: SELECT relation FROM Relation relation JOIN FETCH relation.accounts WHERE relation.key = :key [java.lang.String] 
at org.apache.openjpa.jdbc.sql.DBDictionary.setUnknown(DBDictionary.java:1458) 
at org.apache.openjpa.jdbc.sql.SQLBuffer.setParameters(SQLBuffer.java:544) 
at org.apache.openjpa.jdbc.sql.SQLBuffer.prepareStatement(SQLBuffer.java:453) 
at org.apache.openjpa.jdbc.sql.SQLBuffer.prepareStatement(SQLBuffer.java:429) 
at org.apache.openjpa.jdbc.sql.SelectImpl.prepareStatement(SelectImpl.java:479) 
... 

如果我改變EAGER關係懶,我沒有這個錯誤了。所以有什麼問題 ?

編輯1:我得到同樣的錯誤,如果我繼續oneToOne關係與LAZY獲取類型,並添加直接加入的namedQuery FETCH a.entityC

編輯2:從abstractEntity類實體Ç刪除關係oneToOne和添加這個關係直接進入EntityA和EntityB(加上修改實體C與A & B有反向關係),仍然保持這個onetoOne關係,因爲EAGER =>沒問題。 所以看起來問題來自將這個共享關係放入抽象實體類中,但爲什麼?

這是代碼示例說明了問題。

實體A

@Entity 
@Table(name = "TABLE_A") 
@Access(AccessType.FIELD) 
@NamedQueries({ 
    @NamedQuery(name = "findADetails", query = "SELECT a FROM A a WHERE a.customKey.key  = :customKey")}) 
public class A extends abstractEntity { 

    @Embedded 
    private CustomEmbeddedKey customKey; 

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "entityA") 
    private List<B> bEntities; 

    ... 
} 

實體B

@Entity 
@Table(name = "TABLE_B") 
@Access(AccessType.FIELD) 
public class B extends abstractEntity { 

    @ManyToOne(fetch = FetchType.LAZY, targetEntity = A.class) 
    @JoinColumn(name = "FK_A_ID") 
    private A entityA; 

    ... 
} 

抽象實體類

@Entity 
@Access(AccessType.FIELD) 
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) 
@SequenceGenerator(name = "TOTO_ID_SEQ", sequenceName = "TOTO_ID_SEQ", initialValue = 1, allocationSize = 1) 
public abstract class abstractEntity { 

    @Id 
    @Column(name = "ID") 
    @GeneratedValue(generator = "TOTO_ID_SEQ", strategy = GenerationType.SEQUENCE) 
    private Long id; 

    @OneToOne(mappedBy = "...", fetch = FetchType.EAGER) 
    private C anotherEntity; 

    @OneToMany(mappedBy = "...", fetch = FetchType.LAZY) 
    private List<D> anotherEntities; 

    ... 

} 

嵌入式關鍵

@Embeddable 
@Access(AccessType.FIELD) 
public class CustomEmbeddedKey { 

    @Column(name = "...", length = ...) 
    private String key; 

    ... 
} 

道樣品

TypedQuery<A> query = createNamedQuery("findADetails", A.class); 
    query.setParameter("customKey", queryParam); 
    List<A> aEntitiesFound = query.getResultList(); 

在此先感謝您的幫助。

回答

1

想我發現了這個問題。這是由於它沒有真正的OpenJPA支持的映射,如果我們參考文檔上Eager Fetching Considerations and Limitations

所以最後有我兩個解決方案:


解決方案1(容易的):

  • 更改獲取類型渴望懶抽象實體類
  • 添加取出組,並更新每個相關namedQueries或代碼

優點:

  • 快速的解決方案,並沒有大量的現有代碼影響。

缺點:

  • 必須探討新LAZY領域的使用相關的查詢+更新,因爲這將是現在懶每干將加載(從更新namedQueries如果不)
  • 運行測試與Junit和動態增強仍然會拋出NPE,同時在具有此類映射的namedQueries上執行JOIN FETCH(抽象& TABLE_PER_CLASS繼承類型)

解決方案2:修改映射

  • 從抽象的實體,刪除繼承的使用(其實沒有什麼商業用途)和@MappedSuperclass替換(等去除@Entity和@Inheritance)
  • 添加一個接口並定義EAGER屬性的獲取者/設置者
  • 將此接口實現爲抽象實體類,以便子類必須實現getter/setter(以及相關的屬性和映射)
  • 將這些EAGER對象的目標實體上的反轉關係的類型從抽象類類型更改爲新的接口類型
  • 最後將EAGER屬性的映射,獲取器和設置器的實現從抽象實體類移動到所有子實體類。

優點:

  • 沒有更多的異常(也不NPE由於舊映射和動態類增強)
  • 更強的解決方案,因爲更多的機會,以避免進一步的例外,由於對老OpenJPA的限制映射風格

缺點:

  • 多個修飾
  • 也許少由於接口而不是抽象類型成爲對象實體類
開發者可讀
相關問題