diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java index 2d3a30bb5..6682754cb 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java @@ -380,6 +380,14 @@ public final class PersistRequestBean extends PersistRequest implements BeanP return intercept.dirtyPropertyNames(); } + public boolean isChangedProperty(int propertyIndex) { + if (dirtyProperties == null) { + return intercept.isChangedProperty(propertyIndex); + } else { + return dirtyProperties[propertyIndex]; + } + } + /** * Return the dirty properties on this request. */ @@ -865,8 +873,8 @@ public final class PersistRequestBean extends PersistRequest implements BeanP } setNotifyCache(); boolean isChangeLog = beanDescriptor.isChangeLog(); - if (type == Type.UPDATE && (isChangeLog || notifyCache || docStoreMode == DocStoreMode.UPDATE)) { - // get the dirty properties for update notification to the doc store + if (type == Type.UPDATE) { + // get the dirty properties for notify cache & orphanRemoval of vanilla collection detection dirtyProperties = intercept.dirtyProperties(); } if (isChangeLog) { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/persist/SaveManyBeans.java b/ebean-core/src/main/java/io/ebeaninternal/server/persist/SaveManyBeans.java index e3ccabbff..e82c16961 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/persist/SaveManyBeans.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/persist/SaveManyBeans.java @@ -328,7 +328,7 @@ final class SaveManyBeans extends SaveManyBase { } private boolean isChangedProperty() { - return parentBean._ebean_getIntercept().isChangedProperty(many.propertyIndex()); + return request.isChangedProperty(many.propertyIndex()); } private void removeAssocManyOrphans() { diff --git a/ebean-test/src/test/java/org/tests/model/orphanremoval/OmBeanListParent.java b/ebean-test/src/test/java/org/tests/model/orphanremoval/OmBeanListParent.java index 1aacb79d6..026199f70 100644 --- a/ebean-test/src/test/java/org/tests/model/orphanremoval/OmBeanListParent.java +++ b/ebean-test/src/test/java/org/tests/model/orphanremoval/OmBeanListParent.java @@ -2,10 +2,14 @@ package org.tests.model.orphanremoval; import io.ebean.Model; +import io.ebean.annotation.WhenCreated; +import io.ebean.annotation.WhenModified; import jakarta.persistence.Entity; import jakarta.persistence.Id; import jakarta.persistence.OneToMany; import jakarta.persistence.Version; + +import java.time.Instant; import java.util.List; import static jakarta.persistence.CascadeType.ALL; @@ -19,6 +23,13 @@ public class OmBeanListParent extends Model { @Version private long version; + private String name; + + @WhenCreated + private Instant whenCreated; + @WhenModified + private Instant whenModified; + @OneToMany(cascade = ALL, mappedBy = "parent", orphanRemoval = true) private List children; @@ -35,6 +46,42 @@ public class OmBeanListParent extends Model { this.children.clear(); this.children.addAll(children); } + + public void setChildren2(List children) { + this.children = children; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public long getVersion() { + return version; + } + + public void setVersion(long version) { + this.version = version; + } + + public Instant getWhenModified() { + return whenModified; + } + + public void setWhenModified(Instant whenModified) { + this.whenModified = whenModified; + } + + public Instant getWhenCreated() { + return whenCreated; + } + + public void setWhenCreated(Instant whenCreated) { + this.whenCreated = whenCreated; + } } diff --git a/ebean-test/src/test/java/org/tests/o2m/OneToManyListMarkAsDirtyTest.java b/ebean-test/src/test/java/org/tests/o2m/OneToManyListMarkAsDirtyTest.java new file mode 100644 index 000000000..ae358b85d --- /dev/null +++ b/ebean-test/src/test/java/org/tests/o2m/OneToManyListMarkAsDirtyTest.java @@ -0,0 +1,114 @@ +package org.tests.o2m; + +import io.ebean.DB; +import io.ebean.xtest.BaseTestCase; +import org.junit.jupiter.api.Test; +import org.tests.model.orphanremoval.OmBeanListChild; +import org.tests.model.orphanremoval.OmBeanListParent; +import java.time.Instant; +import java.util.ArrayList; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.LockSupport; + +import static org.assertj.core.api.Assertions.assertThat; + +class OneToManyListMarkAsDirtyTest extends BaseTestCase { + @Test + void usingNewListWithNonDirtyParent_expect_orphanDeleted_works() { + // setup + var parent = new OmBeanListParent(); + var a_b = new OmBeanListChild("b"); + parent.getChildren().add(a_b); + DB.save(parent); + LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(1)); + + // act + var secondParent = DB.find(OmBeanListParent.class, parent.getId()); + secondParent.setChildren2(new ArrayList<>()); //