From 3bf9dd6743382056cd0a96096386575a7c9ee8cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sn=C5=8Dwball?= Date: Thu, 23 May 2019 16:04:40 +0200 Subject: [PATCH] Testcase for ebean with circular dependences 1. While the javax.persistance api discourages the use of bidirectional cascades, it does not prohibit them. They're very useful and natural if you think of the database as a graph instead of a tree. test case 1 (testCircularCascade) tests this. 2. Second test case fetches the child, but saves the parent. If used like that, the child will not have it's changes saved. --- .../tests/update/TestUpdateCircularSave.java | 75 +++++++++++++++++++ .../java/org/tests/update/objects/Child.java | 52 +++++++++++++ .../java/org/tests/update/objects/Parent.java | 43 +++++++++++ .../org/tests/update/objects/SiblingA.java | 43 +++++++++++ .../org/tests/update/objects/SiblingB.java | 53 +++++++++++++ 5 files changed, 266 insertions(+) create mode 100644 src/test/java/org/tests/update/TestUpdateCircularSave.java create mode 100644 src/test/java/org/tests/update/objects/Child.java create mode 100644 src/test/java/org/tests/update/objects/Parent.java create mode 100644 src/test/java/org/tests/update/objects/SiblingA.java create mode 100644 src/test/java/org/tests/update/objects/SiblingB.java diff --git a/src/test/java/org/tests/update/TestUpdateCircularSave.java b/src/test/java/org/tests/update/TestUpdateCircularSave.java new file mode 100644 index 000000000..34b78c760 --- /dev/null +++ b/src/test/java/org/tests/update/TestUpdateCircularSave.java @@ -0,0 +1,75 @@ +package org.tests.update; + +import static org.junit.Assert.assertTrue; + +import io.ebean.BaseTestCase; +import io.ebean.Ebean; +import org.junit.Test; +import org.tests.update.objects.SiblingA; +import org.tests.update.objects.Parent; +import org.tests.update.objects.SiblingB; +import org.tests.update.objects.Child; + +public class TestUpdateCircularSave extends BaseTestCase { + + @Test + public void testCircularCascade() { + + long aId = createA(); + modifyPropertyToTrue(aId); + + SiblingA siblingA = Ebean.find(SiblingA.class, aId); + assert siblingA != null; + assertTrue(siblingA.getSiblingB().isTestProperty()); + } + + private void modifyPropertyToTrue(long aId) { + SiblingA siblingA = Ebean.find(SiblingA.class, aId); + assert siblingA != null; + + final SiblingB siblingB = siblingA.getSiblingB(); + siblingB.setTestProperty(true); + // Will get optimistic lock as version is increased twice on B + Ebean.save(siblingB); + } + + private long createA() { + SiblingA siblingA = new SiblingA(); + SiblingB siblingB = new SiblingB(); + siblingA.setSiblingB(siblingB); + + Ebean.save(siblingA); + return siblingA.getId(); + } + + + @Test + public void testFetchChildSaveParent() { + + long dId = createCAndD(); + modifyPropertyToTrue2(dId); + + Parent parent = Ebean.find(Parent.class, dId); + assert parent != null; + // Fails here because D was not saved even though C has cascade = ALL + assertTrue(parent.getChild().isTestProperty()); + } + + private void modifyPropertyToTrue2(long dId) { + Child child = Ebean.find(Child.class, dId); + assert child != null; + + child.setTestProperty(true); + final Parent parent = child.getParent(); + Ebean.save(parent); + } + + private long createCAndD() { + Parent parent = new Parent(); + Child child = new Child(); + parent.setChild(child); + + Ebean.save(parent); + return parent.getChild().getId(); + } +} diff --git a/src/test/java/org/tests/update/objects/Child.java b/src/test/java/org/tests/update/objects/Child.java new file mode 100644 index 000000000..37a70d9b6 --- /dev/null +++ b/src/test/java/org/tests/update/objects/Child.java @@ -0,0 +1,52 @@ +package org.tests.update.objects; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.OneToOne; +import javax.persistence.Table; +import javax.persistence.Version; + +@Entity +@Table(name = "e_save_test_d") +public class Child { + @Id + private Long id; + @Version + private long version = 0L; + @OneToOne(mappedBy = "child") + private Parent parent; + + private boolean testProperty = false; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public long getVersion() { + return version; + } + + public void setVersion(long version) { + this.version = version; + } + + public Parent getParent() { + return parent; + } + + public void setParent(Parent parent) { + this.parent = parent; + } + + public boolean isTestProperty() { + return testProperty; + } + + public void setTestProperty(boolean testProperty) { + this.testProperty = testProperty; + } +} diff --git a/src/test/java/org/tests/update/objects/Parent.java b/src/test/java/org/tests/update/objects/Parent.java new file mode 100644 index 000000000..edd587969 --- /dev/null +++ b/src/test/java/org/tests/update/objects/Parent.java @@ -0,0 +1,43 @@ +package org.tests.update.objects; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.OneToOne; +import javax.persistence.Table; +import javax.persistence.Version; + +@Entity +@Table(name = "e_save_test_c") +public class Parent { + @Id + private Long id; + @Version + private long version = 0L; + @OneToOne(cascade = CascadeType.ALL) + private Child child; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public long getVersion() { + return version; + } + + public void setVersion(long version) { + this.version = version; + } + + public Child getChild() { + return child; + } + + public void setChild(Child child) { + this.child = child; + } +} diff --git a/src/test/java/org/tests/update/objects/SiblingA.java b/src/test/java/org/tests/update/objects/SiblingA.java new file mode 100644 index 000000000..2e5806657 --- /dev/null +++ b/src/test/java/org/tests/update/objects/SiblingA.java @@ -0,0 +1,43 @@ +package org.tests.update.objects; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.OneToOne; +import javax.persistence.Table; +import javax.persistence.Version; + +@Entity +@Table(name = "e_save_test_a") +public class SiblingA { + @Id + private Long id; + @Version + private long version = 0L; + @OneToOne(cascade = CascadeType.ALL, mappedBy = "siblingA") + private SiblingB siblingB; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public long getVersion() { + return version; + } + + public void setVersion(long version) { + this.version = version; + } + + public SiblingB getSiblingB() { + return siblingB; + } + + public void setSiblingB(SiblingB siblingB) { + this.siblingB = siblingB; + } +} diff --git a/src/test/java/org/tests/update/objects/SiblingB.java b/src/test/java/org/tests/update/objects/SiblingB.java new file mode 100644 index 000000000..63b358645 --- /dev/null +++ b/src/test/java/org/tests/update/objects/SiblingB.java @@ -0,0 +1,53 @@ +package org.tests.update.objects; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.OneToOne; +import javax.persistence.Table; +import javax.persistence.Version; + +@Entity +@Table(name = "e_save_test_b") +public class SiblingB { + @Id + private Long id; + @Version + private long version = 0L; + @OneToOne(cascade = CascadeType.ALL) + private SiblingA siblingA; + + private boolean testProperty = false; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public long getVersion() { + return version; + } + + public void setVersion(long version) { + this.version = version; + } + + public SiblingA getSiblingA() { + return siblingA; + } + + public void setSiblingA(SiblingA siblingA) { + this.siblingA = siblingA; + } + + public boolean isTestProperty() { + return testProperty; + } + + public void setTestProperty(boolean testProperty) { + this.testProperty = testProperty; + } +}