diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransaction.java b/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransaction.java index d26ab3ecc..6708d1a45 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransaction.java @@ -130,7 +130,7 @@ public interface SpiTransaction extends Transaction { Boolean getBatchGetGeneratedKeys(); /** - * Modify and return the current 'depth' of the transaction. + * Modify the current 'depth' of the transaction. *

* As we cascade save or delete we traverse the object graph tree. Going up * to Assoc Ones the depth decreases and going down to Assoc Manys the depth @@ -139,12 +139,31 @@ public interface SpiTransaction extends Transaction { * The depth is used for ordering batching statements. The lowest depth get * executed first during save. */ - void depth(int diff); + default void depth(int diff) { + // do nothing + } + + /** + * Decrement the depth BUT only if depth is greater than 0. + * Return the amount that depth should be incremented by (0 or 1). + */ + default void depthDecrement() { + // do nothing + } + + /** + * Reset the depth back to 0 - done at the end of top level insert and update. + */ + default void depthReset() { + // do nothing + } /** * Return the current depth. */ - int depth(); + default int depth() { + return 0; + } /** * Return true if dirty beans are automatically persisted. diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransactionProxy.java b/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransactionProxy.java index 03824903b..c4f81bcab 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransactionProxy.java +++ b/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransactionProxy.java @@ -342,6 +342,16 @@ public abstract class SpiTransactionProxy implements SpiTransaction { transaction.depth(diff); } + @Override + public void depthDecrement() { + transaction.depthDecrement(); + } + + @Override + public void depthReset() { + transaction.depthReset(); + } + @Override public int depth() { return transaction.depth(); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequest.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequest.java index 1eab09911..3d30f70b3 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequest.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequest.java @@ -50,6 +50,13 @@ public abstract class PersistRequest extends BeanRequest implements BatchPostExe this.label = label; } + /** + * Reset the transaction depth back to 0. + */ + public void resetDepth() { + transaction.depthReset(); + } + @Override public void addTimingBatch(long startNanos, int size) { // nothing by default diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java b/ebean-core/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java index 5a8346372..97f30cd8b 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java @@ -251,6 +251,7 @@ public final class DefaultPersister implements Persister { } else { update(request); } + request.resetDepth(); } draftHandler.updateDrafts(transaction, mgr); @@ -417,7 +418,7 @@ public final class DefaultPersister implements Persister { } else { update(req); } - + req.resetDepth(); req.commitTransIfRequired(); req.flushBatchOnCascade(); @@ -455,6 +456,7 @@ public final class DefaultPersister implements Persister { try { req.initTransIfRequiredWithBatchCascade(); insert(req); + req.resetDepth(); req.commitTransIfRequired(); req.flushBatchOnCascade(); @@ -1123,7 +1125,7 @@ public final class DefaultPersister implements Persister { && !prop.isReference(detailBean) && !request.isParent(detailBean)) { SpiTransaction t = request.transaction(); - t.depth(-1); + t.depthDecrement(); saveRecurse(detailBean, t, null, request.flags()); t.depth(+1); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/ImplicitReadOnlyTransaction.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/ImplicitReadOnlyTransaction.java index 4948eb9ef..a0b0bb06d 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/ImplicitReadOnlyTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/ImplicitReadOnlyTransaction.java @@ -232,18 +232,6 @@ final class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEve throw new IllegalStateException(notExpectedMessage); } - @Override - public void depth(int diff) { - } - - /** - * Return the current depth. - */ - @Override - public int depth() { - return 0; - } - @Override public void markNotQueryOnly() { } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java index b1909b1f8..1cd7118c4 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java @@ -484,34 +484,28 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { return existingBean.equals(beanName); } - /** - * Return the depth of the current persist request plus the diff. This has the - * effect of changing the current depth and returning the new value. Pass - * diff=0 to return the current depth. - *

- * The depth of 0 is for the initial persist request. It is modified as the - * cascading of the save or delete traverses to the the associated Ones (-1) - * and associated Manys (+1). - *

- *

- * The depth is used to help the ordering of batched statements. - *

- * - * @param diff the amount to add or subtract from the depth. - */ @Override public final void depth(int diff) { depth += diff; } - /** - * Return the current depth. - */ @Override public final int depth() { return depth; } + @Override + public final void depthDecrement() { + if (depth != 0) { + depth += -1; + } + } + + @Override + public final void depthReset() { + depth = 0; + } + @Override public final void markNotQueryOnly() { this.queryOnly = false; diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/NoTransaction.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/NoTransaction.java index 8bccacfc6..9c043dfe9 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/NoTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/NoTransaction.java @@ -310,15 +310,6 @@ final class NoTransaction implements SpiTransaction { return null; } - @Override - public void depth(int diff) { - } - - @Override - public int depth() { - return 0; - } - @Override public boolean isExplicit() { return false; diff --git a/ebean-test/src/test/java/io/ebeaninternal/server/transaction/TransactionTest.java b/ebean-test/src/test/java/io/ebeaninternal/server/transaction/TransactionTest.java index 374e4519e..c4bb4aafd 100644 --- a/ebean-test/src/test/java/io/ebeaninternal/server/transaction/TransactionTest.java +++ b/ebean-test/src/test/java/io/ebeaninternal/server/transaction/TransactionTest.java @@ -7,10 +7,11 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.tests.model.basic.relates.*; -public class TransactionTest extends BaseTestCase { - private Relation1 r1 = new Relation1("R1"); - private Relation2 r2 = new Relation2("R2"); - private Relation3 r3 = new Relation3("R3"); +class TransactionTest extends BaseTestCase { + + private final Relation1 r1 = new Relation1("R1"); + private final Relation2 r2 = new Relation2("R2"); + private final Relation3 r3 = new Relation3("R3"); private Transaction txn; @@ -27,14 +28,14 @@ public class TransactionTest extends BaseTestCase { } @Test - public void testMultiSave1() { + void testMultiSave1() { r2.setWithCascade(r3); r1.setWithCascade(r2); DB.save(r1); } @Test - public void testMultiSave2() { + void testMultiSave2() { r2.setWithCascade(r3); r1.setWithCascade(r2); DB.save(r3); @@ -42,7 +43,7 @@ public class TransactionTest extends BaseTestCase { } @Test - public void testMultiSave3() { + void testMultiSave3() { r2.setWithCascade(r3); r1.setWithCascade(r2); DB.save(r3); @@ -51,7 +52,7 @@ public class TransactionTest extends BaseTestCase { } @Test - public void testMultiSave4() { + void testMultiSave4() { r2.setNoCascade(r3); r1.setWithCascade(r2); DB.save(r3); @@ -60,11 +61,20 @@ public class TransactionTest extends BaseTestCase { } @Test - public void testMultiSave5() { + void testMultiSave4_usingRelation4() { + Relation4 r4 = new Relation4("foo"); + r2.setR4NoCascade(r4); + r1.setWithCascade(r2); + DB.save(r4); + DB.save(r1); + } + + @Test + void testMultiSave5() { r2.setNoCascade(r3); r1.setNoCascade(r2); DB.save(r3); DB.save(r2); DB.save(r1); } -} \ No newline at end of file +} diff --git a/ebean-test/src/test/java/org/tests/model/basic/relates/Relation2.java b/ebean-test/src/test/java/org/tests/model/basic/relates/Relation2.java index 2af3bc4cb..a84ff7eb0 100644 --- a/ebean-test/src/test/java/org/tests/model/basic/relates/Relation2.java +++ b/ebean-test/src/test/java/org/tests/model/basic/relates/Relation2.java @@ -1,12 +1,14 @@ package org.tests.model.basic.relates; -import java.util.UUID; - -import javax.persistence.*; - import io.ebean.annotation.ChangeLog; +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.ManyToOne; +import java.util.UUID; + /** * Relation entity */ @@ -23,6 +25,9 @@ public class Relation2 { this.name = name; } + @ManyToOne + private Relation4 r4NoCascade; + @ManyToOne private Relation3 noCascade; @@ -60,5 +65,12 @@ public class Relation2 { public void setWithCascade(Relation3 withCascade) { this.withCascade = withCascade; } - + + public Relation4 getR4NoCascade() { + return r4NoCascade; + } + + public void setR4NoCascade(Relation4 r4NoCascade) { + this.r4NoCascade = r4NoCascade; + } } diff --git a/ebean-test/src/test/java/org/tests/model/basic/relates/Relation4.java b/ebean-test/src/test/java/org/tests/model/basic/relates/Relation4.java new file mode 100644 index 000000000..9e2109f09 --- /dev/null +++ b/ebean-test/src/test/java/org/tests/model/basic/relates/Relation4.java @@ -0,0 +1,42 @@ +package org.tests.model.basic.relates; + + +import io.ebean.annotation.ChangeLog; + +import javax.persistence.Entity; +import javax.persistence.Id; +import java.util.UUID; + +/** + * Relation entity + */ +@Entity +@ChangeLog +public class Relation4 { + + @Id + private UUID id = UUID.randomUUID(); + + private String name; + + public Relation4(String name) { + this.name = name; + } + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + +}