diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/SpiBeanType.java b/ebean-core/src/main/java/io/ebeaninternal/api/SpiBeanType.java index 9923fff3f8..89c2548ac0 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/api/SpiBeanType.java +++ b/ebean-core/src/main/java/io/ebeaninternal/api/SpiBeanType.java @@ -14,4 +14,9 @@ public interface SpiBeanType { * or removals from the collection. */ boolean isToManyDirty(EntityBean bean); + + /** + * returns the ID of the bean. + */ + Object getId(EntityBean bean); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/DefaultPersistenceContext.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/DefaultPersistenceContext.java index 3ede05de11..3ba4beaec1 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/DefaultPersistenceContext.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/DefaultPersistenceContext.java @@ -311,9 +311,11 @@ private void deleted(Object id) { deleteSet = new HashSet<>(); } deleteSet.add(id); - remove(id); } + private boolean isDeleted(EntityBean bean) { + return deleteSet != null && deleteSet.contains(rootType); + } /** * Add the dirty beans to the list. */ @@ -325,7 +327,12 @@ void dirtyBeans(SpiBeanTypeManager manager, List list) { if (value == null) continue; } EntityBean bean = (EntityBean) value; - if (bean._ebean_getIntercept().isDirty() || beanType.isToManyDirty(bean)) { + boolean deleted = false; + if (deleteSet != null) { + Object id = beanType.getId(bean); + deleted = id != null && deleteSet.contains(id); + } + if (!deleted && bean._ebean_getIntercept().isDirty() || beanType.isToManyDirty(bean)) { list.add(value); } } diff --git a/ebean-test/src/test/java/io/ebean/xtest/event/BeanPersistControllerTest.java b/ebean-test/src/test/java/io/ebean/xtest/event/BeanPersistControllerTest.java index e89b808a95..1388f28969 100644 --- a/ebean-test/src/test/java/io/ebean/xtest/event/BeanPersistControllerTest.java +++ b/ebean-test/src/test/java/io/ebean/xtest/event/BeanPersistControllerTest.java @@ -2,13 +2,15 @@ import io.ebean.Database; +import io.ebean.DatabaseBuilder; import io.ebean.DatabaseFactory; import io.ebean.Transaction; -import io.ebean.DatabaseBuilder; import io.ebean.config.DatabaseConfig; import io.ebean.event.BeanDeleteIdRequest; import io.ebean.event.BeanPersistAdapter; +import io.ebean.event.BeanPersistController; import io.ebean.event.BeanPersistRequest; +import io.ebean.test.LoggedSql; import org.junit.jupiter.api.Test; import org.tests.model.basic.EBasicVer; import org.tests.model.basic.UTDetail; @@ -132,7 +134,7 @@ public void testInsertUpdateDelete_given_stopPersistingAdapter() { assertThat(stopPersistingAdapter.methodsCalled).containsExactly("preDeleteById"); stopPersistingAdapter.methodsCalled.clear(); - db.deleteAll(EBasicVer.class, Arrays.asList(22,23,24)); + db.deleteAll(EBasicVer.class, Arrays.asList(22, 23, 24)); assertThat(stopPersistingAdapter.methodsCalled).hasSize(3); assertThat(stopPersistingAdapter.methodsCalled).containsExactly("preDeleteById", "preDeleteById", "preDeleteById"); stopPersistingAdapter.methodsCalled.clear(); @@ -140,7 +142,116 @@ public void testInsertUpdateDelete_given_stopPersistingAdapter() { db.shutdown(); } - private Database getDatabase(PersistAdapter persistAdapter) { + @Test + public void testCascade() { + Database db = getDatabase(new BeanPersistAdapter() { + @Override + public boolean isRegisterFor(Class cls) { + return UTMaster.class == cls; + } + + @Override + public boolean preDelete(BeanPersistRequest request) { + return false; + } + }); + Integer id; + UTMaster master = new UTMaster(); + master.addDetail(new UTDetail()); + db.save(master); + id = master.getId(); + + master = db.find(UTMaster.class, id); + assertThat(master.getDetails()).hasSize(1); + + try (Transaction txn = db.beginTransaction()) { + txn.setBatchMode(true); + db.delete(master); + txn.commit(); + } + + master = db.find(UTMaster.class, id); + assertThat(master).isNotNull(); + // CHECKME: Deleting of master was denied by the PersistListener + // What about detail? Is this intended, that it will be deleted? + assertThat(master.getDetails()).hasSize(0); + + } + + @Test + public void testInsertUpdateDelete_with_LazyLoad() { + + Database db = getDatabase(new BeanPersistAdapter() { + + @Override + public boolean isRegisterFor(Class cls) { + return EBasicVer.class == cls; + } + + @Override + public boolean preInsert(BeanPersistRequest request) { + assertThat(((EBasicVer) request.bean()).getDescription()).isEqualTo("MyDescription"); + return true; + } + + @Override + public boolean preUpdate(BeanPersistRequest request) { + assertThat(((EBasicVer) request.bean()).getDescription()).isEqualTo("MyDescription"); + return true; + } + + @Override + public boolean preDelete(BeanPersistRequest request) { + assertThat(((EBasicVer) request.bean()).getDescription()).isEqualTo("MyDescription"); + return true; + } + }); + Integer id; + try (Transaction txn = db.beginTransaction()) { + txn.setBatchMode(true); + EBasicVer bean = new EBasicVer("testController"); + bean.setDescription("MyDescription"); + + db.save(bean); + txn.commit(); + id = bean.getId(); + } + + + try (Transaction txn = db.beginTransaction()) { + txn.setBatchMode(true); + EBasicVer bean = db.find(EBasicVer.class).setUseCache(false).select("name").setId(id).findOne(); + bean.setName("otherName"); + + db.save(bean); + + txn.commitAndContinue(); + + EBasicVer bean2 = db.find(EBasicVer.class).setUseCache(false).select("name").setId(id).findOne(); + assertThat(bean2).isSameAs(bean); + } + + try (Transaction txn = db.beginTransaction()) { + txn.setBatchMode(true); + EBasicVer bean = db.find(EBasicVer.class).setUseCache(false).select("name").setId(id).findOne(); + + db.delete(bean); + txn.commitAndContinue(); + System.out.println(txn); + } +/* + db.update(bean); + + db.delete(bean); + + db.delete(EBasicVer.class, 22); + + db.deleteAll(EBasicVer.class, Arrays.asList(22,23,24)); +*/ + db.shutdown(); + } + + private Database getDatabase(BeanPersistController persistAdapter) { DatabaseBuilder config = new DatabaseConfig(); config.setName("h2ebasicver"); config.loadFromProperties(); @@ -194,12 +305,12 @@ public boolean preUpdate(BeanPersistRequest request) { Object bean = request.bean(); if (bean instanceof UTDetail) { - UTDetail detail = (UTDetail)bean; + UTDetail detail = (UTDetail) bean; // invoke lazy loading ... which invoke the flush of the jdbc batch detail.setQty(42); } if (bean instanceof UTMaster) { - UTMaster master = (UTMaster)bean; + UTMaster master = (UTMaster) bean; UTMaster.Journal journal = master.getJournal(); if (journal == null) { journal = new UTMaster.Journal();