Skip to content

Commit 0baaeb3

Browse files
authored
Merge pull request #10216 from emyasa/BAEL-4643
BAEL-4643: JPA CascadeType.REMOVE vs orphanRemoval
2 parents 22caadc + bc501e3 commit 0baaeb3

6 files changed

Lines changed: 315 additions & 21 deletions

File tree

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package com.baeldung.jpa.removal;
2+
3+
import javax.persistence.Entity;
4+
import javax.persistence.GeneratedValue;
5+
import javax.persistence.GenerationType;
6+
import javax.persistence.Id;
7+
import javax.persistence.ManyToOne;
8+
import java.util.Objects;
9+
10+
@Entity
11+
public class LineItem {
12+
13+
@Id
14+
@GeneratedValue(strategy = GenerationType.AUTO)
15+
private Long id;
16+
17+
private String name;
18+
19+
@ManyToOne
20+
private OrderRequest orderRequest;
21+
22+
public LineItem(String name) {
23+
this.name = name;
24+
}
25+
26+
@Override
27+
public boolean equals(Object o) {
28+
if (this == o)
29+
return true;
30+
if (o == null || getClass() != o.getClass())
31+
return false;
32+
33+
LineItem lineItem = (LineItem) o;
34+
35+
return Objects.equals(id, lineItem.id);
36+
}
37+
38+
@Override
39+
public int hashCode() {
40+
return id != null ? id.hashCode() : 0;
41+
}
42+
43+
protected LineItem() {
44+
}
45+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package com.baeldung.jpa.removal;
2+
3+
import javax.persistence.CascadeType;
4+
import javax.persistence.Entity;
5+
import javax.persistence.GeneratedValue;
6+
import javax.persistence.GenerationType;
7+
import javax.persistence.Id;
8+
import javax.persistence.OneToMany;
9+
import javax.persistence.OneToOne;
10+
import java.util.List;
11+
12+
@Entity
13+
public class OrderRequest {
14+
15+
@Id
16+
@GeneratedValue(strategy = GenerationType.AUTO)
17+
private Long id;
18+
19+
@OneToOne(cascade = { CascadeType.REMOVE, CascadeType.PERSIST })
20+
private ShipmentInfo shipmentInfo;
21+
22+
@OneToMany(orphanRemoval = true, cascade = CascadeType.PERSIST, mappedBy = "orderRequest")
23+
private List<LineItem> lineItems;
24+
25+
public OrderRequest(ShipmentInfo shipmentInfo) {
26+
this.shipmentInfo = shipmentInfo;
27+
}
28+
29+
public OrderRequest(List<LineItem> lineItems) {
30+
this.lineItems = lineItems;
31+
}
32+
33+
public void removeLineItem(LineItem lineItem) {
34+
lineItems.remove(lineItem);
35+
}
36+
37+
public void setLineItems(List<LineItem> lineItems) {
38+
this.lineItems = lineItems;
39+
}
40+
41+
protected OrderRequest() {
42+
}
43+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.baeldung.jpa.removal;
2+
3+
import javax.persistence.Entity;
4+
import javax.persistence.GeneratedValue;
5+
import javax.persistence.GenerationType;
6+
import javax.persistence.Id;
7+
8+
@Entity
9+
public class ShipmentInfo {
10+
11+
@Id
12+
@GeneratedValue(strategy = GenerationType.AUTO)
13+
private Long id;
14+
15+
private String name;
16+
17+
public ShipmentInfo(String name) {
18+
this.name = name;
19+
}
20+
21+
protected ShipmentInfo() {
22+
}
23+
}
Lines changed: 39 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,43 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
3-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4-
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
55
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd"
6-
version="2.2">
7-
<persistence-unit name="jpa-h2-equality">
8-
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
9-
<class>com.baeldung.jpa.equality.EqualByJavaDefault</class>
10-
<class>com.baeldung.jpa.equality.EqualById</class>
11-
<class>com.baeldung.jpa.equality.EqualByBusinessKey</class>
12-
<exclude-unlisted-classes>true</exclude-unlisted-classes>
13-
<properties>
14-
<property name="javax.persistence.jdbc.driver" value="org.h2.Driver" />
15-
<property name="javax.persistence.jdbc.url" value="jdbc:h2:mem:test" />
16-
<property name="javax.persistence.jdbc.user" value="sa" />
17-
<property name="javax.persistence.jdbc.password" value="" />
18-
<property name="javax.persistence.jdbc.driver" value="org.h2.Driver" />
19-
<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
20-
<property name="hibernate.hbm2ddl.auto" value="create-drop" />
21-
<property name="show_sql" value="false" />
22-
<property name="hibernate.temp.use_jdbc_metadata_defaults" value="false" />
23-
</properties>
24-
</persistence-unit>
6+
version="2.2">
7+
<persistence-unit name="jpa-h2-equality">
8+
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
9+
<class>com.baeldung.jpa.equality.EqualByJavaDefault</class>
10+
<class>com.baeldung.jpa.equality.EqualById</class>
11+
<class>com.baeldung.jpa.equality.EqualByBusinessKey</class>
12+
<exclude-unlisted-classes>true</exclude-unlisted-classes>
13+
<properties>
14+
<property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
15+
<property name="javax.persistence.jdbc.url" value="jdbc:h2:mem:test"/>
16+
<property name="javax.persistence.jdbc.user" value="sa"/>
17+
<property name="javax.persistence.jdbc.password" value=""/>
18+
<property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
19+
<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
20+
<property name="hibernate.hbm2ddl.auto" value="create-drop"/>
21+
<property name="show_sql" value="false"/>
22+
<property name="hibernate.temp.use_jdbc_metadata_defaults" value="false"/>
23+
</properties>
24+
</persistence-unit>
25+
<persistence-unit name="jpa-h2-removal">
26+
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
27+
<class>com.baeldung.jpa.removal.ShipmentInfo</class>
28+
<class>com.baeldung.jpa.removal.LineItem</class>
29+
<class>com.baeldung.jpa.removal.OrderRequest</class>
30+
<exclude-unlisted-classes>true</exclude-unlisted-classes>
31+
<properties>
32+
<property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
33+
<property name="javax.persistence.jdbc.url" value="jdbc:h2:mem:test"/>
34+
<property name="javax.persistence.jdbc.user" value="sa"/>
35+
<property name="javax.persistence.jdbc.password" value=""/>
36+
<property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
37+
<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
38+
<property name="hibernate.hbm2ddl.auto" value="create-drop"/>
39+
<property name="show_sql" value="false"/>
40+
<property name="hibernate.temp.use_jdbc_metadata_defaults" value="false"/>
41+
</properties>
42+
</persistence-unit>
2543
</persistence>
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package com.baeldung.jpa.removal;
2+
3+
import org.junit.Assert;
4+
import org.junit.BeforeClass;
5+
import org.junit.Test;
6+
7+
import javax.persistence.EntityManager;
8+
import javax.persistence.EntityManagerFactory;
9+
import javax.persistence.Persistence;
10+
import javax.persistence.TypedQuery;
11+
import javax.persistence.criteria.CriteriaBuilder;
12+
import javax.persistence.criteria.CriteriaQuery;
13+
import javax.persistence.criteria.Root;
14+
import java.util.List;
15+
16+
public class CascadeTypeRemoveIntegrationTest {
17+
18+
private static EntityManagerFactory factory;
19+
private static EntityManager entityManager;
20+
21+
@BeforeClass
22+
public static void setup() {
23+
factory = Persistence.createEntityManagerFactory("jpa-h2-removal");
24+
entityManager = factory.createEntityManager();
25+
}
26+
27+
@Test
28+
public void whenOrderRequestIsDeleted_thenDeleteShipmentInfo() {
29+
createOrderRequestWithShipmentInfo();
30+
31+
OrderRequest orderRequest = entityManager.find(OrderRequest.class, 1L);
32+
33+
entityManager.getTransaction().begin();
34+
entityManager.remove(orderRequest);
35+
entityManager.getTransaction().commit();
36+
37+
Assert.assertEquals(0, findAllOrderRequest().size());
38+
Assert.assertEquals(0, findAllShipmentInfo().size());
39+
}
40+
41+
private void createOrderRequestWithShipmentInfo() {
42+
ShipmentInfo shipmentInfo = new ShipmentInfo("name");
43+
OrderRequest orderRequest = new OrderRequest(shipmentInfo);
44+
45+
entityManager.getTransaction().begin();
46+
entityManager.persist(orderRequest);
47+
entityManager.getTransaction().commit();
48+
49+
Assert.assertEquals(1, findAllOrderRequest().size());
50+
Assert.assertEquals(1, findAllShipmentInfo().size());
51+
}
52+
53+
private List<OrderRequest> findAllOrderRequest() {
54+
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
55+
CriteriaQuery<OrderRequest> cq = cb.createQuery(OrderRequest.class);
56+
Root<OrderRequest> root = cq.from(OrderRequest.class);
57+
CriteriaQuery<OrderRequest> findAll = cq.select(root);
58+
TypedQuery<OrderRequest> findAllQuery = entityManager.createQuery(findAll);
59+
60+
return findAllQuery.getResultList();
61+
}
62+
63+
private List<ShipmentInfo> findAllShipmentInfo() {
64+
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
65+
CriteriaQuery<ShipmentInfo> cq = cb.createQuery(ShipmentInfo.class);
66+
Root<ShipmentInfo> root = cq.from(ShipmentInfo.class);
67+
CriteriaQuery<ShipmentInfo> findAll = cq.select(root);
68+
TypedQuery<ShipmentInfo> findAllQuery = entityManager.createQuery(findAll);
69+
70+
return findAllQuery.getResultList();
71+
}
72+
73+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package com.baeldung.jpa.removal;
2+
3+
import org.junit.Assert;
4+
import org.junit.Before;
5+
import org.junit.Test;
6+
7+
import javax.persistence.EntityManager;
8+
import javax.persistence.EntityManagerFactory;
9+
import javax.persistence.Persistence;
10+
import javax.persistence.PersistenceException;
11+
import javax.persistence.TypedQuery;
12+
import javax.persistence.criteria.CriteriaBuilder;
13+
import javax.persistence.criteria.CriteriaQuery;
14+
import javax.persistence.criteria.Root;
15+
import java.util.ArrayList;
16+
import java.util.List;
17+
18+
public class OrphanRemovalIntegrationTest {
19+
20+
private static EntityManagerFactory factory;
21+
private static EntityManager entityManager;
22+
23+
@Before
24+
public void setup() {
25+
factory = Persistence.createEntityManagerFactory("jpa-h2-removal");
26+
entityManager = factory.createEntityManager();
27+
}
28+
29+
@Test
30+
public void whenLineItemIsRemovedFromOrderRequest_thenDeleteOrphanedLineItem() {
31+
createOrderRequestWithLineItems();
32+
33+
OrderRequest orderRequest = entityManager.find(OrderRequest.class, 1L);
34+
LineItem lineItem = entityManager.find(LineItem.class, 2L);
35+
orderRequest.removeLineItem(lineItem);
36+
37+
entityManager.getTransaction().begin();
38+
entityManager.merge(orderRequest);
39+
entityManager.getTransaction().commit();
40+
41+
Assert.assertEquals(1, findAllOrderRequest().size());
42+
Assert.assertEquals(2, findAllLineItem().size());
43+
}
44+
45+
@Test(expected = PersistenceException.class)
46+
public void whenLineItemsIsReassigned_thenThrowAnException() {
47+
createOrderRequestWithLineItems();
48+
49+
OrderRequest orderRequest = entityManager.find(OrderRequest.class, 1L);
50+
orderRequest.setLineItems(new ArrayList<>());
51+
52+
entityManager.getTransaction().begin();
53+
entityManager.merge(orderRequest);
54+
entityManager.getTransaction().commit();
55+
}
56+
57+
private void createOrderRequestWithLineItems() {
58+
List<LineItem> lineItems = new ArrayList<>();
59+
lineItems.add(new LineItem("line item 1"));
60+
lineItems.add(new LineItem("line item 2"));
61+
lineItems.add(new LineItem("line item 3"));
62+
63+
OrderRequest orderRequest = new OrderRequest(lineItems);
64+
65+
entityManager.getTransaction().begin();
66+
entityManager.persist(orderRequest);
67+
entityManager.getTransaction().commit();
68+
69+
Assert.assertEquals(1, findAllOrderRequest().size());
70+
Assert.assertEquals(3, findAllLineItem().size());
71+
}
72+
73+
private List<OrderRequest> findAllOrderRequest() {
74+
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
75+
CriteriaQuery<OrderRequest> cq = cb.createQuery(OrderRequest.class);
76+
Root<OrderRequest> root = cq.from(OrderRequest.class);
77+
CriteriaQuery<OrderRequest> findAll = cq.select(root);
78+
TypedQuery<OrderRequest> findAllQuery = entityManager.createQuery(findAll);
79+
80+
return findAllQuery.getResultList();
81+
}
82+
83+
private List<LineItem> findAllLineItem() {
84+
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
85+
CriteriaQuery<LineItem> cq = cb.createQuery(LineItem.class);
86+
Root<LineItem> root = cq.from(LineItem.class);
87+
CriteriaQuery<LineItem> findAll = cq.select(root);
88+
TypedQuery<LineItem> findAllQuery = entityManager.createQuery(findAll);
89+
90+
return findAllQuery.getResultList();
91+
}
92+
}

0 commit comments

Comments
 (0)