2010-07-23 78 views
0

我有一個自我連接查詢,看起來像這樣,SqlResultSetMapping與自我連接表

select t1。 ,t2。從表t1 左外側上t2.LFT < t1.LFT 和t2.RGT加入表t2> t1.RGT AND t2.REG_CODE_PAR = 'ALL' AND t1.STATUS_CODE = 'A' AND t2.STATUS_CODE ='A'

我使用@NamedNativeQuery和結果集映射來獲得結果。

@NamedNativeQuery(
    name="findTree", 
    query="..... the query above", 
    resultSetMapping = "regionT") 

得到下面的結果集映射

@SqlResultSetMapping(name = "regionT" , entities ={ 
    @EntityResult( 
     entityClass = Tree.class 
     fields = { 
      @FieldResult(name = "regCode", column = "REG_CODE") 
      @FieldResult(name = "rgt", column = "RGT"), 
      @FieldResult(name = "lft", column = "LFT"), 
      @FieldResult(name = "name", column = "NAME"), 
      @FieldResult(name = "regCodePar", column = "REG_CODE_PAR"), 
      @FieldResult(name = "statusCode", column = "STATUS_CODE") 
     } 
    ), 
    @EntityResult(
     entityClass = TreeSelf.class 
     fields = { 
      @FieldResult(name = "regCode1", column = "REG_CODE") 
      @FieldResult(name = "rgt1", column = "RGT"), 
      @FieldResult(name = "lft1", column = "LFT"), 
      @FieldResult(name = "name1", column = "NAME"), 
      @FieldResult(name = "regCodePar1", column = "REG_CODE_PAR"), 
      @FieldResult(name = "statusCode1", column = "STATUS_CODE") 
     } 
    ) 
}) 

實體類包含這個樣子的。

@NamedNativeQuery(...) 
@SqlResultSetMapping(...) 
@Entity 
@Table(name = "table") 
public class Tree implements Serializable { 

    @Id 
    @Column(name = "REG_CODE") 
    private String regCode; ... ..getters and setters...} 

當運行使用em.createQuery(「findTree」)查詢,我得到在兩個

的第一和返回的對象陣列的第二元件完全相同的對象。 即使我創建一個名爲TreeSelf類是相同的樹,並用它作爲第二

EntityResult而是採用了相同的entityClass有2個EntityResults,我會得到相同的

結果。

有人能指出配置有什麼問題嗎?

+0

您的意思是打印'select t1。*,t2。*'而不是'select t1。,t2.'?看起來格式化程序絆住了你。 – 2010-07-23 06:03:36

回答

1

讓我們看看我是否理解你的問題。您期望從每個本機查詢結果行中捕獲兩個Tree實體。第一個實體應該由t1的列組成。第二個實體應該由t2的列組成。與預期相反,您實際上會收到來自t1的兩個實例。不會出現t2的實例。在進行調試時,您爲Tree創建了一個doppelganger實體,調用TreeSelf,但TreeSelf最終是不必要的,您希望擺脫它。如果有任何錯誤,請阻止我。

我認爲這個問題是由於列名不明確。本機查詢中的每個列名都會出現兩次,一次是t1,一次是t2。結果映射器似乎是任意選擇Tree實體的每個不明確列名的第一次出現。我很驚訝,完全可以工作。我會期待SQLException抱怨列參考含糊不清。

此外,你確定你想要一個左外連接嗎?如果t1行沒有找到匹配項,該怎麼辦?它將與t2的列中的所有NULL配對。然後你有一個空值的Tree實體。我認爲。我甚至不知道結果映射器在這種情況下會做什麼。也許你想要一個內部連接?

考慮將此本機查詢翻譯成JPQL查詢。 (JPA Criteria API也是如此,但我發現它更麻煩的例子。)以下是本機查詢的JPQL版本:

SELECT t1, t2 
FROM Tree t1, Tree t2 
WHERE t2.lft < t1.lft AND t2.rgt > t1.rgt AND t2.regCodePar = 'ALL' AND 
     t1.statusCode = 'A' AND t2.statusCode = 'A' 

N.B.:這會將連接語義更改爲內層而不是左外層。

這裏是代碼的草圖,可能運行此查詢:

EntityManager em = ... // EntityManager by injection, EntityManagerFactory, etc. 
String jpql  = ... // Like example above 
TypedQuery<Object[]> q = em.createQuery(jpql, Object[].class); 

for (Object[] oa : q.getResultList()) { 
    Tree t1 = (Tree)oa[0]; 
    Tree t2 = (Tree)oa[1]; 
} 

如果你被卡住無論什麼原因,本地查詢,這裏是你如何能解決列名不確定性。而不是像select t1.*, t2.*那樣啓動本機查詢,而是使用AS替換每列。該SELECT條款將類似於此:

SELECT t1.REG_CODE AS t1_REG_CODE, t1.RGT AS t1_RGT, (... rest of t1 cols ...), 
     t2.REG_CODE AS t2_REG_CODE, t2.RGT AS t2_RGT, (... rest of t2 cols ...) 

每個FieldResultcolumn屬性必須相應地改變。因此,第一個EntityResult下的column屬性應該全部以t1_開頭,第二個應該全部以t2_開頭。

我會虛心推薦刪除原生查詢和sql結果映射器,並使用JPA查詢語言或Criteria API,如果你能找到一種方法。

更新:如您的評論中所確認的,對您的問題的有用答案必須保留左(外部)連接語義。不幸的是,JPQL和Criteria API不支持複雜的左連接條件。沒有辦法以明確的ON條件限定JPQL左連接。

據我所知,在規範下做左外連接的唯一方法是遍歷實體關係。 JPA實現然後生成測試身份相等性的ON條件。相關的規格位是4.4.5「聯接」和4.4.5.2「左外部聯接」。

爲了滿足這個限制,每個Tree你想要連接到它的最終父母必須有一個額外的列存儲最終父母的ID。你可能會以各種方式(視圖?)繞過這個約束。但阻力最小的路徑似乎在修改本地查詢以使用別名參數,刪除TreeSelf並相應地更新結果映射器。雖然... Cleverer解決方案歡迎您...

+0

嗨丹,謝謝你的洞察力。 是的,你正確理解我的問題,但讓我給你一些歷史。 這是系統中現有的查詢。我的目標是將其轉換爲JPA Criteria API,但由於左連接有多個條件而遇到問題(是需要左連接,空應用程序是在應用程序中處理的)。我發佈這個問題在這裏:http://stackoverflow.com/questions/3280381/how-to-specify-multiple-conditions-on-left-join-using-jpa-criteria-api – Jonathan 2010-07-26 04:46:30

+0

JPQL我面臨的另一個問題是,樹數據結構是表中的一個層次結構。 每一行都有一個列(parent_id),它引用表中另一行的PK。 通過做@ManyToOne @JoinColumn(name =「parent_id」) 私人樹樹; 我會得到它的直接父母。 本機查詢中t2的結果實際上返回頂級父記錄,而不是直接父級。 使用JPQL,我必須Tree.getTree()。​​getTree()。​​getTree()..... getTree()達到6或7級以獲得頂級父級。 – Jonathan 2010-07-26 05:02:36

+0

所有這些說,我的首選是使用JPA標準,如果多條件連接和頂級父問題可以解決。如果您有意見,我非常希望聽到它。謝謝 – Jonathan 2010-07-26 05:07:39