From d3da953252511500578caef6aec9f41984e96ec1 Mon Sep 17 00:00:00 2001 From: Emmanuel Yasa Date: Thu, 29 Oct 2020 00:16:53 +0800 Subject: [PATCH 1/3] BAEL-4643: JPA CascadeType.REMOVE vs orphanRemoval * Defines the Domain: ShipmentInfo, LineItem and OrderRequest entity * Adds CascadeTypeRemoveIntegrationTest * Adds OrphanRemovalIntegrationTest --- .../com/baeldung/jpa/removal/LineItem.java | 42 ++++++++++ .../baeldung/jpa/removal/OrderRequest.java | 38 +++++++++ .../baeldung/jpa/removal/ShipmentInfo.java | 22 ++++++ .../main/resources/META-INF/persistence.xml | 18 +++++ .../CascadeTypeRemoveIntegrationTest.java | 72 +++++++++++++++++ .../removal/OrphanRemovalIntegrationTest.java | 78 +++++++++++++++++++ 6 files changed, 270 insertions(+) create mode 100644 persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/removal/LineItem.java create mode 100644 persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/removal/OrderRequest.java create mode 100644 persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/removal/ShipmentInfo.java create mode 100644 persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/removal/CascadeTypeRemoveIntegrationTest.java create mode 100644 persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/removal/OrphanRemovalIntegrationTest.java diff --git a/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/removal/LineItem.java b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/removal/LineItem.java new file mode 100644 index 0000000000..c926785acc --- /dev/null +++ b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/removal/LineItem.java @@ -0,0 +1,42 @@ +package com.baeldung.jpa.removal; + +import java.util.Objects; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.ManyToOne; + +@Entity +public class LineItem { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + + private String name; + + @ManyToOne + private OrderRequest orderRequest; + + public LineItem(String name) { + this.name = name; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + LineItem lineItem = (LineItem) o; + + return Objects.equals(id, lineItem.id); + } + + @Override + public int hashCode() { + return id != null ? id.hashCode() : 0; + } + + protected LineItem() {} +} diff --git a/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/removal/OrderRequest.java b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/removal/OrderRequest.java new file mode 100644 index 0000000000..ada0459054 --- /dev/null +++ b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/removal/OrderRequest.java @@ -0,0 +1,38 @@ +package com.baeldung.jpa.removal; + +import java.util.List; +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.OneToMany; +import javax.persistence.OneToOne; + +@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 lineItems; + + public OrderRequest(ShipmentInfo shipmentInfo) { + this.shipmentInfo = shipmentInfo; + } + + public OrderRequest(List lineItems) { + this.lineItems = lineItems; + } + + public void removeLineItem(LineItem lineItem) { + lineItems.remove(lineItem); + } + + protected OrderRequest() {} +} diff --git a/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/removal/ShipmentInfo.java b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/removal/ShipmentInfo.java new file mode 100644 index 0000000000..67c8151801 --- /dev/null +++ b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/removal/ShipmentInfo.java @@ -0,0 +1,22 @@ +package com.baeldung.jpa.removal; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +@Entity +public class ShipmentInfo { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + + private String name; + + public ShipmentInfo(String name) { + this.name = name; + } + + protected ShipmentInfo() {} +} diff --git a/persistence-modules/java-jpa-3/src/main/resources/META-INF/persistence.xml b/persistence-modules/java-jpa-3/src/main/resources/META-INF/persistence.xml index 28a929f912..39d55695c4 100644 --- a/persistence-modules/java-jpa-3/src/main/resources/META-INF/persistence.xml +++ b/persistence-modules/java-jpa-3/src/main/resources/META-INF/persistence.xml @@ -22,4 +22,22 @@ + + org.hibernate.jpa.HibernatePersistenceProvider + com.baeldung.jpa.removal.ShipmentInfo + com.baeldung.jpa.removal.LineItem + com.baeldung.jpa.removal.OrderRequest + true + + + + + + + + + + + + diff --git a/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/removal/CascadeTypeRemoveIntegrationTest.java b/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/removal/CascadeTypeRemoveIntegrationTest.java new file mode 100644 index 0000000000..11050a14ee --- /dev/null +++ b/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/removal/CascadeTypeRemoveIntegrationTest.java @@ -0,0 +1,72 @@ +package com.baeldung.jpa.removal; + +import java.util.List; +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.Persistence; +import javax.persistence.TypedQuery; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class CascadeTypeRemoveIntegrationTest { + + private static EntityManagerFactory factory; + private static EntityManager entityManager; + + @BeforeClass + public static void setup() { + factory = Persistence.createEntityManagerFactory("jpa-h2-removal"); + entityManager = factory.createEntityManager(); + } + + @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()); + } + + private List findAllOrderRequest() { + CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + CriteriaQuery cq = cb.createQuery(OrderRequest.class); + Root root = cq.from(OrderRequest.class); + CriteriaQuery findAll = cq.select(root); + TypedQuery findAllQuery = entityManager.createQuery(findAll); + + return findAllQuery.getResultList(); + } + + private List findAllShipmentInfo() { + CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + CriteriaQuery cq = cb.createQuery(ShipmentInfo.class); + Root root = cq.from(ShipmentInfo.class); + CriteriaQuery findAll = cq.select(root); + TypedQuery findAllQuery = entityManager.createQuery(findAll); + + return findAllQuery.getResultList(); + } + +} diff --git a/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/removal/OrphanRemovalIntegrationTest.java b/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/removal/OrphanRemovalIntegrationTest.java new file mode 100644 index 0000000000..75bb321ef4 --- /dev/null +++ b/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/removal/OrphanRemovalIntegrationTest.java @@ -0,0 +1,78 @@ +package com.baeldung.jpa.removal; + +import java.util.ArrayList; +import java.util.List; +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.Persistence; +import javax.persistence.TypedQuery; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class OrphanRemovalIntegrationTest { + + private static EntityManagerFactory factory; + private static EntityManager entityManager; + + @BeforeClass + public static void setup() { + factory = Persistence.createEntityManagerFactory("jpa-h2-removal"); + entityManager = factory.createEntityManager(); + } + + @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 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()); + } + + private List findAllOrderRequest() { + CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + CriteriaQuery cq = cb.createQuery(OrderRequest.class); + Root root = cq.from(OrderRequest.class); + CriteriaQuery findAll = cq.select(root); + TypedQuery findAllQuery = entityManager.createQuery(findAll); + + return findAllQuery.getResultList(); + } + + private List findAllLineItem() { + CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + CriteriaQuery cq = cb.createQuery(LineItem.class); + Root root = cq.from(LineItem.class); + CriteriaQuery findAll = cq.select(root); + TypedQuery findAllQuery = entityManager.createQuery(findAll); + + return findAllQuery.getResultList(); + } +} From e66514e3ddf1d5123b4bab4f2cffe8af5a9c0818 Mon Sep 17 00:00:00 2001 From: Emmanuel Yasa Date: Tue, 3 Nov 2020 19:11:44 +0800 Subject: [PATCH 2/3] BAEL-4643: JPA CascadeType.REMOVE vs orphanRemoval * Reformats code using the provided intelliJ-formatter.xml --- .../com/baeldung/jpa/removal/LineItem.java | 11 ++- .../baeldung/jpa/removal/OrderRequest.java | 5 +- .../baeldung/jpa/removal/ShipmentInfo.java | 3 +- .../main/resources/META-INF/persistence.xml | 78 +++++++++---------- .../CascadeTypeRemoveIntegrationTest.java | 9 ++- .../removal/OrphanRemovalIntegrationTest.java | 11 +-- 6 files changed, 62 insertions(+), 55 deletions(-) diff --git a/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/removal/LineItem.java b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/removal/LineItem.java index c926785acc..9ab2dd4e74 100644 --- a/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/removal/LineItem.java +++ b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/removal/LineItem.java @@ -1,11 +1,11 @@ package com.baeldung.jpa.removal; -import java.util.Objects; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.ManyToOne; +import java.util.Objects; @Entity public class LineItem { @@ -25,8 +25,10 @@ public class LineItem { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; LineItem lineItem = (LineItem) o; @@ -38,5 +40,6 @@ public class LineItem { return id != null ? id.hashCode() : 0; } - protected LineItem() {} + protected LineItem() { + } } diff --git a/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/removal/OrderRequest.java b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/removal/OrderRequest.java index ada0459054..16ee3e0109 100644 --- a/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/removal/OrderRequest.java +++ b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/removal/OrderRequest.java @@ -1,6 +1,5 @@ package com.baeldung.jpa.removal; -import java.util.List; import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.GeneratedValue; @@ -8,6 +7,7 @@ import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToMany; import javax.persistence.OneToOne; +import java.util.List; @Entity public class OrderRequest { @@ -34,5 +34,6 @@ public class OrderRequest { lineItems.remove(lineItem); } - protected OrderRequest() {} + protected OrderRequest() { + } } diff --git a/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/removal/ShipmentInfo.java b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/removal/ShipmentInfo.java index 67c8151801..12274bcadf 100644 --- a/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/removal/ShipmentInfo.java +++ b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/removal/ShipmentInfo.java @@ -18,5 +18,6 @@ public class ShipmentInfo { this.name = name; } - protected ShipmentInfo() {} + protected ShipmentInfo() { + } } diff --git a/persistence-modules/java-jpa-3/src/main/resources/META-INF/persistence.xml b/persistence-modules/java-jpa-3/src/main/resources/META-INF/persistence.xml index 39d55695c4..88378bd8db 100644 --- a/persistence-modules/java-jpa-3/src/main/resources/META-INF/persistence.xml +++ b/persistence-modules/java-jpa-3/src/main/resources/META-INF/persistence.xml @@ -1,43 +1,43 @@ - - org.hibernate.jpa.HibernatePersistenceProvider - com.baeldung.jpa.equality.EqualByJavaDefault - com.baeldung.jpa.equality.EqualById - com.baeldung.jpa.equality.EqualByBusinessKey - true - - - - - - - - - - - - - - org.hibernate.jpa.HibernatePersistenceProvider - com.baeldung.jpa.removal.ShipmentInfo - com.baeldung.jpa.removal.LineItem - com.baeldung.jpa.removal.OrderRequest - true - - - - - - - - - - - - + version="2.2"> + + org.hibernate.jpa.HibernatePersistenceProvider + com.baeldung.jpa.equality.EqualByJavaDefault + com.baeldung.jpa.equality.EqualById + com.baeldung.jpa.equality.EqualByBusinessKey + true + + + + + + + + + + + + + + org.hibernate.jpa.HibernatePersistenceProvider + com.baeldung.jpa.removal.ShipmentInfo + com.baeldung.jpa.removal.LineItem + com.baeldung.jpa.removal.OrderRequest + true + + + + + + + + + + + + diff --git a/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/removal/CascadeTypeRemoveIntegrationTest.java b/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/removal/CascadeTypeRemoveIntegrationTest.java index 11050a14ee..8f99723ac6 100644 --- a/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/removal/CascadeTypeRemoveIntegrationTest.java +++ b/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/removal/CascadeTypeRemoveIntegrationTest.java @@ -1,6 +1,9 @@ package com.baeldung.jpa.removal; -import java.util.List; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; @@ -8,9 +11,7 @@ import javax.persistence.TypedQuery; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Root; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; +import java.util.List; public class CascadeTypeRemoveIntegrationTest { diff --git a/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/removal/OrphanRemovalIntegrationTest.java b/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/removal/OrphanRemovalIntegrationTest.java index 75bb321ef4..0ab6e4cfbc 100644 --- a/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/removal/OrphanRemovalIntegrationTest.java +++ b/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/removal/OrphanRemovalIntegrationTest.java @@ -1,7 +1,9 @@ package com.baeldung.jpa.removal; -import java.util.ArrayList; -import java.util.List; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; @@ -9,9 +11,8 @@ import javax.persistence.TypedQuery; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Root; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; +import java.util.ArrayList; +import java.util.List; public class OrphanRemovalIntegrationTest { From f6f1c110820789688e9ecbd830f6603e7bbc9724 Mon Sep 17 00:00:00 2001 From: Emmanuel Yasa Date: Wed, 4 Nov 2020 23:38:29 +0800 Subject: [PATCH 3/3] BAEL-4643: JPA CascadeType.REMOVE vs orphanRemoval * Adds a test to OrphanRemovalIntegrationTest that expects a PersistenceException --- .../baeldung/jpa/removal/OrderRequest.java | 4 ++++ .../removal/OrphanRemovalIntegrationTest.java | 19 ++++++++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/removal/OrderRequest.java b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/removal/OrderRequest.java index 16ee3e0109..739c110d8c 100644 --- a/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/removal/OrderRequest.java +++ b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/removal/OrderRequest.java @@ -34,6 +34,10 @@ public class OrderRequest { lineItems.remove(lineItem); } + public void setLineItems(List lineItems) { + this.lineItems = lineItems; + } + protected OrderRequest() { } } diff --git a/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/removal/OrphanRemovalIntegrationTest.java b/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/removal/OrphanRemovalIntegrationTest.java index 0ab6e4cfbc..615e8cf3a8 100644 --- a/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/removal/OrphanRemovalIntegrationTest.java +++ b/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/removal/OrphanRemovalIntegrationTest.java @@ -1,12 +1,13 @@ package com.baeldung.jpa.removal; import org.junit.Assert; -import org.junit.BeforeClass; +import org.junit.Before; import org.junit.Test; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; +import javax.persistence.PersistenceException; import javax.persistence.TypedQuery; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; @@ -19,8 +20,8 @@ public class OrphanRemovalIntegrationTest { private static EntityManagerFactory factory; private static EntityManager entityManager; - @BeforeClass - public static void setup() { + @Before + public void setup() { factory = Persistence.createEntityManagerFactory("jpa-h2-removal"); entityManager = factory.createEntityManager(); } @@ -41,6 +42,18 @@ public class OrphanRemovalIntegrationTest { Assert.assertEquals(2, findAllLineItem().size()); } + @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(); + } + private void createOrderRequestWithLineItems() { List lineItems = new ArrayList<>(); lineItems.add(new LineItem("line item 1"));