2013-03-05 45 views
-1

我剛剛發現EclipseLink(2.3.0和2.4.1)的一個相當奇怪的問題,只是想問問是否有人可以確認這是一個錯誤,而不僅僅是我缺少一些東西顯然...Eclipselink插入實體與0 ID

基本上,我有兩個實體參與,讓我們簡單地稱他們爲A和B.一個渴望(如果有的話),非級聯多對一的單向引用B建模在帶連接列的數據庫。數據庫表A包含列ID(PK),B_ID(FK到B.ID)等等,表B包含列ID等等。

現在,我有一個As的列表,它應該更新並引用新的B實例。在僞代碼類似的:

for(A a : list) { 
    // using some criteria, check if perhaps a matching B 
    // entity is already found in the database 
    B b = perhapsGetExistingBFromDatabase(); 

    if(b == null) { 
     // no existing B was found, create a new 
     b = new B(); 
     // set values in B 
     b.setFoo(4711), 
     b.setBar(42); 

     // save B 
     em.merge(b); 
    } 

    // set reference from A to B ... 
    a.setB(b); 
    // ... and update A 
    em.merge(a); 
} 

由於引用是非級聯的,所以有必要將b和a合併。一切按預期工作。

然後,有人(我)將關係的級聯類型從none改爲merge/persist,因爲這是在代碼中的其他地方需要的。我預計舊代碼工作,合併B是不是真的需要,不應該恕我直言,但傷害?一個簡短的測試證實它仍然有效,插入新的B實體並相應地更新A實體。

但是,它只適用於列表中只有一個A實體。第二次運行循環會導致EclipseLink自動刷新會話,因爲perhapsGetExistingBFromDatabase執行「SELECT .. FROM B」,因此存在合併的B實體緩存,並且希望數據庫表保持最新狀態。在代碼中使用FINEST日誌記錄級別和斷點,我可以驗證EclipseLink是否需要爲新的B實體生成一個id,它調用序列生成器並將該id設置在實體的正確字段中。 EclipseLink調用類似於以下的SQL語句:

INSERT INTO B (ID, ...) VALUES(0, ...); 
UPDATE A SET B_ID = 0 WHERE ID = ...; 

生成的id在某處丟失,EclipseLink嘗試創建id爲0的新實體。數據確實無效,之後,EclipseLink還會拋出一個PersistenceException:在工作單元克隆中遇到空或零主鍵。

錯誤或我的錯誤?


編輯:詹姆斯問B.ID的映射:

@Id 
@GeneratedValue(generator = "sq_idgen", strategy = GenerationType.SEQUENCE) 
@SequenceGenerator(name = "sq_idgen", sequenceName = "...", allocationSize = 100) 
@Column(name = "id") 
protected long id; 

注意,即去除unneccesary em.merge(b);解決我的問題。這對我來說並不明顯,爲什麼調用合併會導致EclipseLink完全失敗,試圖插入沒有填充ID的B實例。

回答

0

這很奇怪,B的Id如何映射?

似乎合併可能以某種方式獲得B的兩個單獨的實例(因爲沒有什麼可以將它們識別爲與沒有Id相同)。不是merge()通常不是必需的,它只對分離的對象是必需的,例如在使用序列化時(嘗試使用persist代替)。

爲避免刷新,您可以將EntityManager或持久單元中的flushMode設置爲COMMIT而不是AUTO。

+0

我已經添加了id映射到我原來的問題。在這種情況下合併b實際上是必需的,因爲它是一個新對象。如果我堅持了它,它的id不會立即更新,並且我不能將它與現有的實例連接起來。在這種情況下,自動刷新模式也是正確的,因爲我可以創建新的B實例,在稍後的循環迭代中可以通過'maybeGetExistingBFromDatabase'找到它。 – jarnbjo 2013-03-05 16:03:04