2017-06-01 127 views
1

我知道similarquestions,但他們被問及在Hibernate的範圍內回答。我遇到了同樣的問題,但我正在使用Eclipselink,並想知道是否有更好的或替代的解決方案來解決Hibernate的問題。使用Eclipselink/JPA更改實體類型?

回顧一下前不久的問題:

我上課,從相互繼承:

@Entity 
@Inheritance(strategy=InheritanceType.SINGLE_TABLE) 
@DiscriminatorColumn(name="dtype") 
@DiscriminatorValue(value="parent") 
public class Parent { 
    @Id 
    private long id; 
} 


@Entity 
@DiscriminatorValue(value="child") 
public class Child extends Parent{ 
    private String childProperty; 
} 

現在我想改變一個孩子到家長或反之亦然,如

Parent p = new Parent(); 
em.persist(p); 

Child c = (Child) p; 
em.merge(c); 

我認爲p的數據庫行現在是dtype = child

另一種方法是這樣的:

Child c = new Child(); 
em.persist(c); 

Parent c = (Parent) c; 
em.merge(c); 

在這種情況下,我希望c被保存dtype = parent和失去childProperty值。

但是,上面所述的內容並不起作用,但我寫下來表明我的意思。

有沒有辦法用Eclipselink做到這一點?

+0

請根據面向對象描述或給出示例代碼,瞭解「更改類型」? –

+0

我擴展了說明 – Bob

+0

看來是不自然的設計,在第一步之後,下一個也是錯誤的。我不太會說流利的英文來描述如何(以我的理解)解決問題 –

回答

2

如果您想將某個對象從一種類型更改爲另一種類型,那麼java或JPA繼承就沒有簡單的解決方案。您必須複製您的實例,去掉舊的,然後堅持新的一個是JPA/Java的兼容:

Child c = em.find(pk, Child.class); 
Parent p = new Parent(); 
p.setId(c.getId()); 
p.setOtherFields(c.getOtherFields()); 

em.getTransaction().begin(); 
em.remove(c); 
em.getTransaction().commit(); 
em.clear(); 
em.getTransaction().begin(); 
em.persist(p); 
em.getTransaction().commit(); 

使用相同的交易,這一切「可能」工作在使用沖洗,而不是提交/開始,但不能保證二次緩存的管理變得棘手。另請注意,所有與子項的關係都需要更新以指向「新」父實例,否則緩存將被損壞。

雖然我不太確定這一點,因爲在這種情況下,子項是父項實例。除了數據庫中的任意標誌之外,這種方法沒有什麼可以獲得的。如果您希望可以隨時更改,那麼使用Java子類可能不適合您的應用程序。

相反,我建議使用一個通用的人,有字段,您可以設置爲保持子/父狀態。但是,因爲一個孩子可以同時成爲父母。

+0

謝謝你的回答。我遇到的這個解決方案的一個問題是'em.remove(c);'也會通過cascade-persist刪除OneToMany相關的對象。你知道任何方法(除了刪除cascade-persist),因爲我需要在新的父對象上的OneToMany-Objects。 – Bob

+0

將它們排除。無論如何您都需要清理任何引用,然後將這些引用添加到新實例中。這不幸的是包括修復雙向引用,並且由於需要額外的語句,所以不會是最有效的方法。如果您沒有使用共享緩存,則可以跳過修復遠程引用以指向新實例,但將來限制應用程序。 – Chris