diff --git a/ebean-test/src/test/java/org/tests/o2m/TestOneToManyStatelessUpdateResultsInSoftDelete.java b/ebean-test/src/test/java/org/tests/o2m/TestOneToManyStatelessUpdateResultsInSoftDelete.java index 5c5784e11..e6e86e5dd 100644 --- a/ebean-test/src/test/java/org/tests/o2m/TestOneToManyStatelessUpdateResultsInSoftDelete.java +++ b/ebean-test/src/test/java/org/tests/o2m/TestOneToManyStatelessUpdateResultsInSoftDelete.java @@ -1,13 +1,16 @@ package org.tests.o2m; +import com.fasterxml.jackson.databind.ObjectMapper; import io.ebean.DB; import io.ebean.test.LoggedSql; import io.ebean.xtest.BaseTestCase; import org.junit.jupiter.api.Test; import org.tests.o2m.dm.GoodsEntity; +import org.tests.o2m.dm.PersonEntity; import org.tests.o2m.dm.WorkflowEntity; import org.tests.o2m.dm.WorkflowOperationEntity; +import java.io.StringWriter; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; @@ -161,4 +164,75 @@ class TestOneToManyStatelessUpdateResultsInSoftDelete extends BaseTestCase { assertThat(ops).hasSize(1); assertThat(goodsStateless.getWorkflowEntity().getOperations().get(0).getId()).isNotEqualTo(operation1.getId()); } + + @Test + void softDeleteIncludedInQuery() throws Exception { + var defaultPerson = new PersonEntity(); + defaultPerson.setName("test"); + DB.save(defaultPerson); + + // create GoodsEntity with 1 WorkflowOperationEntity + var goods = new GoodsEntity(); + goods.setCreatedBy(defaultPerson); + goods.setName("ver1"); + var workflow = new WorkflowEntity(); + workflow.setRevision("ver1"); + var operation1 = new WorkflowOperationEntity(); + operation1.setName("ver1"); + goods.setWorkflowEntity(workflow); + workflow.setOperations(List.of(operation1)); + + DB.save(goods); + + // statelessly delete WorkflowOperationEntity + var goodsStateless = new GoodsEntity(); + goodsStateless.setId(goods.getId()); + var workflowStateless = new WorkflowEntity(); + workflowStateless.setId(workflow.getId()); + goodsStateless.setWorkflowEntity(workflowStateless); + workflowStateless.setOperations(List.of()); + + LoggedSql.start(); + DB.update(goodsStateless); + // uncommenting this lines makes the test pass + //assertThat(goodsStateless.getWorkflowEntity().getOperations().size()).isEqualTo(0); + + var sql = LoggedSql.stop(); + sql.forEach(System.out::println); + + System.out.println("BEFORE TRY"); + LoggedSql.start(); + + try (var writer = new StringWriter()) { + var mapper = new ObjectMapper(); + mapper.writeValue(writer, goodsStateless); + sql = LoggedSql.stop(); + sql.forEach(System.out::println); + /* + select t0.id, t0.name, t0.workflow_entity_id, t0.version, t0.when_created, t0.when_modified from goods_entity t0 where t0.id = ?; --bind(4, ) --micros(161) + select t0.id, t0.name, t0.version, t0.when_created, t0.when_modified, t0.created_by, t0.updated_by, t0.workflow_entity_id from goods_entity t0 where t0.id = ?; --bind(4, ) --micros(525) + select t0.id, t0.name, t0.version, t0.when_created, t0.when_modified from person_entity t0 where t0.id = ?; --bind(1, ) --micros(325) + ! is this even issue? - select does not check if workflow_entity is deleted + select t0.id, t0.revision, t0.version, t0.when_created, t0.when_modified from workflow_entity t0 where t0.id = ?; --bind(1, ) --micros(439) + select t0.id, t0.revision, t0.version, t0.when_created, t0.when_modified, t0.created_by, t0.updated_by from workflow_entity t0 where t0.id = ?; --bind(1, ) --micros(332) + + select t0.id, t0.name, t0.version, t0.when_created, t0.when_modified from person_entity t0 where t0.id = ?; --bind(1, ) --micros(197) + select t0.workflow_id, t0.id, t0.position, t0.name, t0.workflow_id, t0.version, t0.when_created, t0.when_modified, t0.deleted from workflow_operation_entity t0 where (t0.workflow_id) in (?) order by t0.workflow_id, t0.position; --bind(Array[1]={1}) --micros(2776) + select t0.id, t0.position, t0.name, t0.version, t0.when_created, t0.when_modified, t0.deleted, t0.workflow_id, t0.created_by, t0.updated_by from workflow_operation_entity t0 where t0.id = ?; --bind(1, ) --micros(415) + + !! ignores soft delete + also to note - when the DM extends BaseDomain instead of HistoryColumns, this bug does not happen + (presumably since @WhoCreated Person createdBy is lazy loaded, when it is eagerly loaded, this bug does not occur) + select t0.workflow_id, t0.id, t0.position, t0.name, t0.workflow_id, t0.version, t0.when_created, t0.when_modified, t0.deleted from workflow_operation_entity t0 where (t0.workflow_id) in (?) order by t0.workflow_id, t0.position; --bind(Array[1]={4}) --micros(585) + + select t0.id, t0.position, t0.name, t0.version, t0.when_created, t0.when_modified, t0.deleted, t0.created_by, t0.updated_by, t0.workflow_id from workflow_operation_entity t0 where t0.id = ?; --bind(7, ) --micros(532) + */ + + writer.flush(); + var serialized = writer.toString(); + System.out.println(serialized); + var readGoods = mapper.readValue(writer.toString(), GoodsEntity.class); + assertThat(readGoods.getWorkflowEntity().getOperations()).hasSize(0); + } + } } diff --git a/ebean-test/src/test/java/org/tests/o2m/dm/GoodsEntity.java b/ebean-test/src/test/java/org/tests/o2m/dm/GoodsEntity.java index ea8b88b49..7d088f04a 100644 --- a/ebean-test/src/test/java/org/tests/o2m/dm/GoodsEntity.java +++ b/ebean-test/src/test/java/org/tests/o2m/dm/GoodsEntity.java @@ -2,13 +2,10 @@ package org.tests.o2m.dm; import org.tests.model.draftable.BaseDomain; -import javax.persistence.CascadeType; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.OneToOne; +import javax.persistence.*; @Entity -public class GoodsEntity extends BaseDomain { +public class GoodsEntity extends HistoryColumns { private String name; @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true) diff --git a/ebean-test/src/test/java/org/tests/o2m/dm/HistoryColumns.java b/ebean-test/src/test/java/org/tests/o2m/dm/HistoryColumns.java new file mode 100644 index 000000000..978475275 --- /dev/null +++ b/ebean-test/src/test/java/org/tests/o2m/dm/HistoryColumns.java @@ -0,0 +1,39 @@ +package org.tests.o2m.dm; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.ebean.annotation.WhenCreated; +import io.ebean.annotation.WhenModified; +import io.ebean.annotation.WhoCreated; +import io.ebean.annotation.WhoModified; +import org.tests.model.draftable.BaseDomain; + +import javax.persistence.*; +import java.time.LocalDateTime; + +@MappedSuperclass +public class HistoryColumns extends BaseDomain { + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "created_by") + private PersonEntity createdBy; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "updated_by") + private PersonEntity updatedBy; + + + public PersonEntity getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(PersonEntity createdBy) { + this.createdBy = createdBy; + } + + public PersonEntity getUpdatedBy() { + return updatedBy; + } + + public void setUpdatedBy(PersonEntity updatedBy) { + this.updatedBy = updatedBy; + } +} diff --git a/ebean-test/src/test/java/org/tests/o2m/dm/PersonEntity.java b/ebean-test/src/test/java/org/tests/o2m/dm/PersonEntity.java new file mode 100644 index 000000000..6b71ab238 --- /dev/null +++ b/ebean-test/src/test/java/org/tests/o2m/dm/PersonEntity.java @@ -0,0 +1,26 @@ +package org.tests.o2m.dm; + +import org.tests.model.draftable.BaseDomain; + +import javax.persistence.Entity; + +@Entity +public class PersonEntity extends BaseDomain { + + public PersonEntity() { + } + + public PersonEntity(Long id) { + this.setId(id); + } + + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/ebean-test/src/test/java/org/tests/o2m/dm/WorkflowEntity.java b/ebean-test/src/test/java/org/tests/o2m/dm/WorkflowEntity.java index 8ad958297..44a434a40 100644 --- a/ebean-test/src/test/java/org/tests/o2m/dm/WorkflowEntity.java +++ b/ebean-test/src/test/java/org/tests/o2m/dm/WorkflowEntity.java @@ -1,6 +1,9 @@ package org.tests.o2m.dm; +import com.fasterxml.jackson.annotation.JsonProperty; import io.ebean.annotation.SoftDelete; +import io.ebean.annotation.Where; +import io.ebean.annotation.WhoCreated; import org.tests.model.draftable.BaseDomain; import javax.persistence.*; @@ -8,31 +11,15 @@ import java.util.ArrayList; import java.util.List; @Entity -public class WorkflowEntity extends BaseDomain { - private String revision; +public class WorkflowEntity extends HistoryColumns { + private String revision; - @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) - @JoinColumn(name = "workflow_id") - private List operations = new ArrayList<>(); + @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) + @JoinColumn(name = "workflow_id") + private List operations = new ArrayList<>(); - @SoftDelete - private boolean deleted; - - public String getRevision() { - return revision; - } - - public void setRevision(String revision) { - this.revision = revision; - } - - public List getOperations() { - return operations; - } - - public void setOperations(List operations) { - this.operations = operations; - } + @SoftDelete + private boolean deleted; public boolean isDeleted() { return deleted; @@ -41,4 +28,20 @@ public class WorkflowEntity extends BaseDomain { public void setDeleted(boolean deleted) { this.deleted = deleted; } + + public String getRevision() { + return revision; + } + + public void setRevision(String revision) { + this.revision = revision; + } + + public List getOperations() { + return operations; + } + + public void setOperations(List operations) { + this.operations = operations; + } } diff --git a/ebean-test/src/test/java/org/tests/o2m/dm/WorkflowOperationEntity.java b/ebean-test/src/test/java/org/tests/o2m/dm/WorkflowOperationEntity.java index 83d228bd7..e8d862017 100644 --- a/ebean-test/src/test/java/org/tests/o2m/dm/WorkflowOperationEntity.java +++ b/ebean-test/src/test/java/org/tests/o2m/dm/WorkflowOperationEntity.java @@ -1,5 +1,6 @@ package org.tests.o2m.dm; +import com.fasterxml.jackson.annotation.JsonIgnore; import io.ebean.annotation.SoftDelete; import org.tests.model.draftable.BaseDomain; @@ -8,14 +9,13 @@ import java.util.ArrayList; import java.util.List; @Entity -public class WorkflowOperationEntity extends BaseDomain { - +public class WorkflowOperationEntity extends HistoryColumns { private String name; @ManyToOne @JoinColumn(name = "workflow_id") + @JsonIgnore private WorkflowEntity workflowEntity; - @SoftDelete private boolean deleted;