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