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
另外,为了验证实体是否已从我们的数据库中正确删除,我们创建了几个集成测试。
0 评论