From 361df6732a87ebbe4380faf643477d6113fc1721 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Mon, 20 Dec 2021 15:49:58 +1300 Subject: [PATCH] #2472 - BeanPersistController and isCascade() for delete requests (following #2458) --- .../server/persist/DefaultPersister.java | 25 ++++++++++++++----- .../basic/event/TestPreInsertValidation.java | 16 ++++++++++-- .../org/tests/model/basic/TWithPreInsert.java | 4 +-- .../model/basic/TWithPreInsertCommon.java | 2 ++ .../event/TWithPreInsertPersistAdapter.java | 15 +++++++++++ 5 files changed, 52 insertions(+), 10 deletions(-) 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 f2c56db74..701b76402 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 @@ -333,6 +333,13 @@ public final class DefaultPersister implements Persister { * Recursively delete the bean. This calls back to the EbeanServer. */ private int deleteRecurse(EntityBean detailBean, Transaction t, DeleteMode deleteMode) { + return deleteRequest(createDeleteCascade(detailBean, t, deleteMode.persistType())); + } + + /** + * Delete without being a cascade. + */ + private int delete(EntityBean detailBean, Transaction t, DeleteMode deleteMode) { return deleteRequest(createDeleteRequest(detailBean, t, deleteMode.persistType())); } @@ -560,7 +567,7 @@ public final class DefaultPersister implements Persister { } } - private void deleteList(List beanList, SpiTransaction t, DeleteMode deleteMode, boolean children) { + private void deleteCascade(List beanList, SpiTransaction t, DeleteMode deleteMode, boolean children) { if (children) { t.depth(-1); t.checkBatchEscalationOnCollection(); @@ -604,7 +611,7 @@ public final class DefaultPersister implements Persister { for (Object id : ids) { EntityBean bean = descriptor.createEntityBean(); descriptor.convertSetId(id, bean); - int rowCount = deleteRecurse(bean, transaction, deleteMode); + int rowCount = delete(bean, transaction, deleteMode); if (rowCount == -1) { total = -1; } else if (total != -1) { @@ -656,7 +663,7 @@ public final class DefaultPersister implements Persister { t.logSummary("-- DeleteById of " + descriptor.name() + " ids[" + idList + "] requires fetch of foreign key values"); } List beanList = server.findList(q, t); - deleteList(beanList, t, deleteMode, false); + deleteCascade(beanList, t, deleteMode, false); return beanList.size(); } else { @@ -994,6 +1001,8 @@ public final class DefaultPersister implements Persister { executeSqlUpdate(sqlDelete, t); } else { + // TODO: Review first checking if many property is loaded and using the loaded beans + // ... and only using findIdsByParentId() when the many property isn't loaded // Delete recurse using the Id values of the children Object parentId = desc.getId(parentBean); List idsByParentId = many.findIdsByParentId(parentId, null, t, excludeDetailIds, deleteMode.isHard()); @@ -1017,7 +1026,7 @@ public final class DefaultPersister implements Persister { for (Object id : childIds) { refList.add(targetDesc.createReference(id, null)); } - deleteList(refList, t, deleteMode, true); + deleteCascade(refList, t, deleteMode, true); } else { // perform delete by statement if possible delete(targetDesc, null, childIds, t, deleteMode); @@ -1157,6 +1166,10 @@ public final class DefaultPersister implements Persister { return createDeleteRequest(bean, t, type, Flags.ZERO); } + private PersistRequestBean createDeleteCascade(EntityBean bean, Transaction t, Type type) { + return createDeleteRequest(bean, t, type, Flags.RECURSE); + } + @SuppressWarnings({"unchecked"}) private PersistRequestBean createDeleteRequest(Object bean, Transaction t, PersistRequest.Type type, int flags) { BeanManager mgr = beanManager(bean.getClass()); @@ -1167,7 +1180,7 @@ public final class DefaultPersister implements Persister { type = Type.DELETE_SOFT; } - PersistRequestBean request = new PersistRequestBean<>(server, (T)bean, null, mgr, (SpiTransaction) t, persistExecute, type, flags); + PersistRequestBean request = new PersistRequestBean<>(server, (T) bean, null, mgr, (SpiTransaction) t, persistExecute, type, flags); request.initForSoftDelete(); return request; } @@ -1186,7 +1199,7 @@ public final class DefaultPersister implements Persister { */ @SuppressWarnings("unchecked") private BeanManager beanManager(Class cls) { - BeanManager mgr = (BeanManager)beanDescriptorManager.beanManager(cls); + BeanManager mgr = (BeanManager) beanDescriptorManager.beanManager(cls); if (mgr == null) { throw new PersistenceException(errNotRegistered(cls)); } diff --git a/ebean-test/src/test/java/org/tests/basic/event/TestPreInsertValidation.java b/ebean-test/src/test/java/org/tests/basic/event/TestPreInsertValidation.java index c67e63c4a..8b86b1f87 100644 --- a/ebean-test/src/test/java/org/tests/basic/event/TestPreInsertValidation.java +++ b/ebean-test/src/test/java/org/tests/basic/event/TestPreInsertValidation.java @@ -6,6 +6,7 @@ import io.ebean.DB; import org.junit.jupiter.api.Test; import org.tests.model.basic.TWithPreInsert; import org.tests.model.basic.TWithPreInsertChild; +import org.tests.model.basic.event.TWithPreInsertPersistAdapter; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -27,6 +28,7 @@ class TestPreInsertValidation extends BaseTestCase { assertThat(e.requestCascadeState()).isEqualTo(2); TWithPreInsert e1 = DB.find(TWithPreInsert.class, e.getId()); + assert e1 != null; e1.setTitle("Missus"); DB.save(e1); @@ -54,11 +56,21 @@ class TestPreInsertValidation extends BaseTestCase { assert e1 != null; e1.setTitle("ParentCascading-changed"); - e1.children().get(0).setName("Child0-changed"); + TWithPreInsertChild childBean = e1.children().get(0); + childBean.setName("Child0-changed"); DB.save(e1); assertThat(e1.requestCascadeState()).isEqualTo(12); - assertThat(e1.children().get(0).requestCascadeState()).isEqualTo(11); + assertThat(childBean.requestCascadeState()).isEqualTo(11); + + DB.delete(e1); + + assertThat(e1.requestCascadeState()).isEqualTo(22); + + // assert that isCascade() was true for the child bean + assertThat(TWithPreInsertPersistAdapter.cascadeDelete).hasSize(1); + String deleteCascade = TWithPreInsertPersistAdapter.cascadeDelete.get(0); + assertThat(deleteCascade).isEqualTo("class org.tests.model.basic.TWithPreInsertChild:1"); } @Test diff --git a/ebean-test/src/test/java/org/tests/model/basic/TWithPreInsert.java b/ebean-test/src/test/java/org/tests/model/basic/TWithPreInsert.java index 21398bc7a..acfffce20 100644 --- a/ebean-test/src/test/java/org/tests/model/basic/TWithPreInsert.java +++ b/ebean-test/src/test/java/org/tests/model/basic/TWithPreInsert.java @@ -7,7 +7,7 @@ import javax.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; -import static javax.persistence.CascadeType.PERSIST; +import static javax.persistence.CascadeType.ALL; @Entity public class TWithPreInsert implements TWithPreInsertCommon { @@ -20,7 +20,7 @@ public class TWithPreInsert implements TWithPreInsertCommon { private String title; - @OneToMany(cascade = PERSIST) + @OneToMany(cascade = ALL) private List children = new ArrayList<>(); /** diff --git a/ebean-test/src/test/java/org/tests/model/basic/TWithPreInsertCommon.java b/ebean-test/src/test/java/org/tests/model/basic/TWithPreInsertCommon.java index dc61e28ba..632c7ade9 100644 --- a/ebean-test/src/test/java/org/tests/model/basic/TWithPreInsertCommon.java +++ b/ebean-test/src/test/java/org/tests/model/basic/TWithPreInsertCommon.java @@ -2,6 +2,8 @@ package org.tests.model.basic; public interface TWithPreInsertCommon { + Integer getId(); + String getName(); void setName(String name); diff --git a/ebean-test/src/test/java/org/tests/model/basic/event/TWithPreInsertPersistAdapter.java b/ebean-test/src/test/java/org/tests/model/basic/event/TWithPreInsertPersistAdapter.java index 03143d385..ffc87e00a 100644 --- a/ebean-test/src/test/java/org/tests/model/basic/event/TWithPreInsertPersistAdapter.java +++ b/ebean-test/src/test/java/org/tests/model/basic/event/TWithPreInsertPersistAdapter.java @@ -4,8 +4,13 @@ import io.ebean.event.BeanPersistAdapter; import io.ebean.event.BeanPersistRequest; import org.tests.model.basic.TWithPreInsertCommon; +import java.util.ArrayList; +import java.util.List; + public class TWithPreInsertPersistAdapter extends BeanPersistAdapter { + public static List cascadeDelete = new ArrayList<>(); + @Override public boolean isRegisterFor(Class cls) { return TWithPreInsertCommon.class.isAssignableFrom(cls); @@ -32,4 +37,14 @@ public class TWithPreInsertPersistAdapter extends BeanPersistAdapter { return super.preUpdate(request); } + @Override + public boolean preDelete(BeanPersistRequest request) { + TWithPreInsertCommon bean = (TWithPreInsertCommon) request.bean(); + if (request.isCascade()) { + cascadeDelete.add(bean.getClass() + ":" + bean.getId()); + } else { + bean.requestCascadeState(22); + } + return true; + } }