拨开荷叶行,寻梦已然成。仙女莲花里,翩翩白鹭情。
IMG-LOGO
主页 文章列表 JPA CascadeType.REMOVE对比orphanRemoval

JPA CascadeType.REMOVE对比orphanRemoval

白鹭 - 2021-11-24 767 0 0

1.概述

在本教程中,我们将讨论在使用JPA时从数据库中删除实体的两种选择之间的区别。

首先,我们将从CascadeType.REMOVE开始,这是在删除父实体时删除一个或多个子实体的一种方法。然后,我们来看看JPA 2.0中引入orphanRemoval这为我们提供了一种从数据库中删除孤立实体的方法。

在整个教程中,我们将使用一个简单的在线商店域来演示我们的示例。

2.领域模型

如前所述,本文利用了一个简单的在线商店域。其中, OrderRequest具有ShipmentInfoLineItem列表。

鉴于此,让我们考虑:

  • 为了删除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方法,该方法将LineItemOrderRequest分离。

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

标签:

0 评论

发表评论

您的电子邮件地址不会被公开。 必填的字段已做标记 *