2012-10-30 104 views
2

我有兩個實體類AB分別存在雙向一對多關係。JPA/Hibernate刪除「子」實體

A.java:

@OneToMany(cascade = CascadeType.ALL, mappedBy = "aId", 
      fetch=FetchType.EAGER, orphanRemoval=true) 
private Set<B> bCollection = new LinkedHashSet<B>(); 

B.java

@JoinColumn(name = "A_ID", referencedColumnName = "ID", nullable=false) 
    @ManyToOne(optional = false) 
    private A aId; 

在一個簡單的控制檯應用程序我從數據庫中獲取特定一個行並嘗試刪除一個其詳細信息B行(隨機)但是JPA/Hibernate不僅會刪除該行 - 它甚至不會向數據庫發出任何DELETE語句。刪除行的唯一方法是從集合中刪除相應實體(LinkedHashSetA.java。所以,雖然我有一個解決方法,但我想了解爲什麼下面的代碼失敗,並且也無法安靜地失敗!

public static void main(String[] args) { 
    EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("testjpa"); 
    EntityManager em = entityManagerFactory.createEntityManager(); 
    EntityTransaction entityTransaction = em.getTransaction(); 
    entityTransaction.begin(); 
    A a = em.find(A.class, 1); 
    B b = getARandomChildOfA(a); 
    em.remove(em.merge(b));  // simple em.remove(b) doesn't work either 
    entityTransaction.commit(); 
    em.close(); 
    entityManagerFactory.close(); 
} 

回答

6

JPA不會爲你管理的關係,所以當你已經呼籲B拆下,一個仍然有它的參考。由於引用在其上設置了級聯保持/合併集合,因此會導致b在上下文中復活,並撤銷刪除。

您必須保持引用以保持您的模型與您在數據庫中想要的同步。除非您確定可以處理這種潛在的不一致情況,否則最好刪除對正在刪除的對象的引用並設置指針。

+0

如果我可以做一些澄清:(1)復活發生在哪個呼叫中,有什麼方法可以看到它? (用於測試)(2)我不能總是使用EntityManager :: remove方法去除「頂層」對象(即沒有出現在其他對象的集合中的對象)及其整個圖表嗎? (3)我對「刪除和設置指針的對象的空引用」措辭感到困惑。我所做的是從A的集合中刪除B,並將B :: aId設置爲null。這是你所指的嗎?消除B:儘管如此,似乎是多餘的。這是由JPA規範決定的嗎? –

+1

復活可能發生在comit上,因爲這是應該改變的時候。 2)不確定你的意思。您可以刪除任何實體,但您必須像管理任何java對象一樣管理對它的任何引用。 3)我的意思是空刪除對象的引用。從樹上修剪它們以及將它們移除 – Chris

+0

@Chris保存了我的一天!感謝克里斯。你在第二段中描述的情況完全一樣。 Cascade.remove FTW :-) – Aubergine