JPA CascadeType.REMOVE對比orphanRemoval
- JPA
- java
1.概述
在本教程中,我們將討論在使用JPA時從數據庫中刪除實體的兩種選擇之間的區別。
首先,我們將從CascadeType.REMOVE
開始,這是在刪除父實體時刪除一個或多個子實體的一種方法。然後,我們來看看JPA 2.0中引入orphanRemoval
這為我們提供了一種從數據庫中刪除孤立實體的方法。
在整個教程中,我們將使用一個簡單的在線商店域來演示我們的示例。
2.領域模型
如前所述,本文利用了一個簡單的在線商店域。其中, OrderRequest
具有ShipmentInfo
和LineItem
列表。
鑑於此,讓我們考慮:
- 為了刪除
ShipmentInfo,
當刪除OrderRequest
時,我們將使用CascadeType.REMOVE
- 為了從
OrderRequest
LineItem
,我們將使用orphanRemoval
首先,讓我們創建一個ShipmentInfo
實體:
@Entity
public class ShipmentInfo {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
// constructors
}
接下來,讓我們創建一個LineItem
實體:
@Entity
public class LineItem {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
@ManyToOne
private OrderRequest orderRequest;
// constructors, equals, hashCode
}
最後,讓我們通過創建OrderRequest實體將它們放在一起:
@Entity
public class OrderRequest {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@OneToOne(cascade = { CascadeType.REMOVE, CascadeType.PERSIST })
private ShipmentInfo shipmentInfo;
@OneToMany(orphanRemoval = true, cascade = CascadeType.PERSIST, mappedBy = "orderRequest")
private List<LineItem> lineItems;
// constructors
public void removeLineItem(LineItem lineItem) {
lineItems.remove(lineItem);
}
}
值得強調一下removeLineItem
方法,該方法將LineItem與OrderRequest分離。
3. CascadeType.REMOVE
如前所述,使用CascadeType.REMOVE
標記引用字段是一種刪除**父實體的子實體**的方法。
在我們的示例中, OrderRequest
具有ShipmentInfo
,其具有CascadeType.REMOVE
。
為了驗證刪除ShipmentInfo
從數據庫時刪除OrderRequest
情況發生,讓我們創建一個簡單的集成測試:
@Test
public void whenOrderRequestIsDeleted_thenDeleteShipmentInfo() {
createOrderRequestWithShipmentInfo();
OrderRequest orderRequest = entityManager.find(OrderRequest.class, 1L);
entityManager.getTransaction().begin();
entityManager.remove(orderRequest);
entityManager.getTransaction().commit();
Assert.assertEquals(0, findAllOrderRequest().size());
Assert.assertEquals(0, findAllShipmentInfo().size());
}
private void createOrderRequestWithShipmentInfo() {
ShipmentInfo shipmentInfo = new ShipmentInfo("name");
OrderRequest orderRequest = new OrderRequest(shipmentInfo);
entityManager.getTransaction().begin();
entityManager.persist(orderRequest);
entityManager.getTransaction().commit();
Assert.assertEquals(1, findAllOrderRequest().size());
Assert.assertEquals(1, findAllShipmentInfo().size());
}
從這些斷言中,我們可以看到刪除OrderRequest
成功刪除相關的ShipmentInfo
。
4. orphanRemoval
如前所述,其用法是從數據庫中**刪除**孤立的實體。不再附屬於其父實體的實體被定義為孤兒。
在我們的示例中, OrderRequest
LineItem
對象的集合,其中 我們使用@OneToMany
批註來標識關係.
在這裡,我們還將orphanRemoval
屬性true
。要從OrderRequest
LineItem
,我們可以使用之前創建removeLineItem
一切就緒後,一旦我們使用removeLineItem
方法並保存OrderRequest
,就應該從數據庫中刪除孤立的LineItem
為了驗證從數據庫中刪除孤立的LineItem
,讓我們創建另一個集成測試:
@Test
public void whenLineItemIsRemovedFromOrderRequest_thenDeleteOrphanedLineItem() {
createOrderRequestWithLineItems();
OrderRequest orderRequest = entityManager.find(OrderRequest.class, 1L);
LineItem lineItem = entityManager.find(LineItem.class, 2L);
orderRequest.removeLineItem(lineItem);
entityManager.getTransaction().begin();
entityManager.merge(orderRequest);
entityManager.getTransaction().commit();
Assert.assertEquals(1, findAllOrderRequest().size());
Assert.assertEquals(2, findAllLineItem().size());
}
private void createOrderRequestWithLineItems() {
List<LineItem> lineItems = new ArrayList<>();
lineItems.add(new LineItem("line item 1"));
lineItems.add(new LineItem("line item 2"));
lineItems.add(new LineItem("line item 3"));
OrderRequest orderRequest = new OrderRequest(lineItems);
entityManager.getTransaction().begin();
entityManager.persist(orderRequest);
entityManager.getTransaction().commit();
Assert.assertEquals(1, findAllOrderRequest().size());
Assert.assertEquals(3, findAllLineItem().size());
}
同樣,從斷言中可以看出,我們已成功從數據庫中LineItem
另外,值得一提的是removeLineItem
方法修改LineItem
列表,而不是為其重新分配值。後者將導致PersistenceException
。
為了驗證聲明的行為,讓我們創建一個最終的集成測試:
@Test(expected = PersistenceException.class)
public void whenLineItemsIsReassigned_thenThrowAnException() {
createOrderRequestWithLineItems();
OrderRequest orderRequest = entityManager.find(OrderRequest.class, 1L);
orderRequest.setLineItems(new ArrayList<>());
entityManager.getTransaction().begin();
entityManager.merge(orderRequest);
entityManager.getTransaction().commit();
}
5.結論
在本文中,我們使用一個簡單的在線商店域CascadeType.REMOVE
和orphanRemoval
另外,為了驗證實體是否已從我們的數據庫中正確刪除,我們創建了幾個集成測試。