#118 - ENH: Add support for for Soft Deletes (Logical Deletion) ...

This commit is contained in:
Robin Bygrave
2015-12-02 21:38:34 +13:00
parent 0ad52cf6a7
commit f39a684c8e
16 changed files with 469 additions and 118 deletions
@@ -0,0 +1,72 @@
package com.avaje.tests.model.softdelete;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Version;
@Entity
public class EBasicNoSDChild {
@Id
Long id;
@Version
Long version;
@ManyToOne(optional = false)
EBasicSoftDelete owner;
String childName;
long amount;
public EBasicNoSDChild(EBasicSoftDelete owner, String childName, long amount) {
this.owner = owner;
this.childName = childName;
this.amount = amount;
}
public EBasicNoSDChild() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getVersion() {
return version;
}
public void setVersion(Long version) {
this.version = version;
}
public EBasicSoftDelete getOwner() {
return owner;
}
public void setOwner(EBasicSoftDelete owner) {
this.owner = owner;
}
public String getChildName() {
return childName;
}
public void setChildName(String childName) {
this.childName = childName;
}
public long getAmount() {
return amount;
}
public void setAmount(long amount) {
this.amount = amount;
}
}
@@ -0,0 +1,48 @@
package com.avaje.tests.model.softdelete;
import javax.persistence.Entity;
import javax.persistence.ManyToOne;
@Entity
public class EBasicSDChild extends BaseSoftDelete {
@ManyToOne(optional = false)
EBasicSoftDelete owner;
String childName;
long amount;
public EBasicSDChild(EBasicSoftDelete owner, String childName, long amount) {
this.owner = owner;
this.childName = childName;
this.amount = amount;
}
public EBasicSDChild() {
}
public EBasicSoftDelete getOwner() {
return owner;
}
public void setOwner(EBasicSoftDelete owner) {
this.owner = owner;
}
public String getChildName() {
return childName;
}
public void setChildName(String childName) {
this.childName = childName;
}
public long getAmount() {
return amount;
}
public void setAmount(long amount) {
this.amount = amount;
}
}
@@ -1,6 +1,9 @@
package com.avaje.tests.model.softdelete;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.OneToMany;
import java.util.List;
@Entity
public class EBasicSoftDelete extends BaseSoftDelete {
@@ -9,6 +12,13 @@ public class EBasicSoftDelete extends BaseSoftDelete {
String description;
@OneToMany(mappedBy = "owner", cascade = CascadeType.ALL)
List<EBasicSDChild> children;
@OneToMany(mappedBy = "owner", cascade = CascadeType.ALL)
List<EBasicNoSDChild> nosdChildren;
public String getName() {
return name;
}
@@ -24,4 +34,28 @@ public class EBasicSoftDelete extends BaseSoftDelete {
public void setDescription(String description) {
this.description = description;
}
public List<EBasicSDChild> getChildren() {
return children;
}
public void setChildren(List<EBasicSDChild> children) {
this.children = children;
}
public void addChild(String childName, long amount) {
getChildren().add(new EBasicSDChild(this, childName, amount));
}
public List<EBasicNoSDChild> getNosdChildren() {
return nosdChildren;
}
public void setNosdChildren(List<EBasicNoSDChild> nosdChildren) {
this.nosdChildren = nosdChildren;
}
public void addNoSoftDeleteChild(String childName, long amount) {
getNosdChildren().add(new EBasicNoSDChild(this, childName, amount));
}
}
@@ -0,0 +1,35 @@
package com.avaje.tests.model.softdelete;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.ManyToMany;
import java.util.List;
@Entity
public class ESoftDelRole extends BaseSoftDelete {
String roleName;
@ManyToMany(cascade = CascadeType.ALL)
List<ESoftDelUser> users;
public ESoftDelRole(String roleName) {
this.roleName = roleName;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public List<ESoftDelUser> getUsers() {
return users;
}
public void setUsers(List<ESoftDelUser> users) {
this.users = users;
}
}
@@ -0,0 +1,38 @@
package com.avaje.tests.model.softdelete;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.ManyToMany;
import java.util.List;
@Entity
public class ESoftDelUser extends BaseSoftDelete {
String userName;
@ManyToMany(cascade = CascadeType.ALL)
List<ESoftDelRole> roles;
public ESoftDelUser(String userName) {
this.userName = userName;
}
public ESoftDelUser() {
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public List<ESoftDelRole> getRoles() {
return roles;
}
public void setRoles(List<ESoftDelRole> roles) {
this.roles = roles;
}
}
@@ -2,11 +2,15 @@ package com.avaje.tests.softdelete;
import com.avaje.ebean.BaseTestCase;
import com.avaje.ebean.Ebean;
import com.avaje.ebean.Query;
import com.avaje.ebean.SqlQuery;
import com.avaje.ebean.SqlRow;
import com.avaje.tests.model.softdelete.EBasicSoftDelete;
import org.avaje.ebeantest.LoggedSqlCollector;
import org.junit.Test;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
public class TestSoftDeleteBasic extends BaseTestCase {
@@ -40,4 +44,84 @@ public class TestSoftDeleteBasic extends BaseTestCase {
assertThat(findInclude).isNotNull();
}
@Test
public void testCascadeSaveDelete() {
EBasicSoftDelete bean = new EBasicSoftDelete();
bean.setName("cascadeOne");
bean.addChild("child1", 10);
bean.addChild("child2", 20);
bean.addChild("child3", 30);
bean.addNoSoftDeleteChild("nsd1", 101);
bean.addNoSoftDeleteChild("nsd2", 102);
Ebean.save(bean);
LoggedSqlCollector.start();
Ebean.delete(bean);
List<String> loggedSql = LoggedSqlCollector.stop();
// The children without SoftDelete are left as is (so no third statement)
assertThat(loggedSql).hasSize(2);
// first statement is a single bulk update of the children with SoftDelete
assertThat(loggedSql.get(0)).contains("update ebasic_sdchild set deleted=");
assertThat(loggedSql.get(0)).contains("where owner_id = ?");
// second statement is the top level bean
assertThat(loggedSql.get(1)).contains("update ebasic_soft_delete set version=?, deleted=? where id=? and version=?");
}
@Test
public void testFetch() {
EBasicSoftDelete bean = new EBasicSoftDelete();
bean.setName("cascadeOne");
bean.addChild("child1", 10);
bean.addChild("child2", 20);
bean.addChild("child3", 30);
bean.addNoSoftDeleteChild("nsd1", 101);
bean.addNoSoftDeleteChild("nsd2", 102);
Ebean.save(bean);
Ebean.delete(bean.getChildren().get(1));
LoggedSqlCollector.start();
Query<EBasicSoftDelete> query1 =
Ebean.find(EBasicSoftDelete.class)
.fetch("children")
.where().eq("id", bean.getId())
.query();
List<EBasicSoftDelete> fetch1 = query1.findList();
String generatedSql = query1.getGeneratedSql();
// first statement is a single bulk update of the children with SoftDelete
assertThat(generatedSql).contains("t0.deleted=");
assertThat(generatedSql).contains("t1.deleted=");
assertThat(fetch1.get(0).getChildren()).hasSize(2);
assertThat(fetch1.get(0).getNosdChildren()).hasSize(2);
// fetch again using lazy loading
EBasicSoftDelete fetchWithLazy = Ebean.find(EBasicSoftDelete.class, bean.getId());
assertThat(fetchWithLazy.getChildren()).hasSize(2);
// fetch includeSoftDeletes using lazy loading
EBasicSoftDelete fetchAllWithLazy =
Ebean.find(EBasicSoftDelete.class)
.setId(bean.getId())
.includeSoftDeletes()
.findUnique();
assertThat(fetchAllWithLazy.getChildren()).hasSize(3);
}
}
@@ -0,0 +1,43 @@
package com.avaje.tests.softdelete;
import com.avaje.ebean.BaseTestCase;
import com.avaje.ebean.Ebean;
import com.avaje.tests.model.softdelete.ESoftDelRole;
import com.avaje.tests.model.softdelete.ESoftDelUser;
import org.avaje.ebeantest.LoggedSqlCollector;
import org.junit.Test;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
public class TestSoftDeleteManyToMany extends BaseTestCase {
@Test
public void test() {
ESoftDelRole role1 = new ESoftDelRole("role1");
ESoftDelRole role2 = new ESoftDelRole("role2");
Ebean.save(role1);
Ebean.save(role2);
ESoftDelUser user1 = new ESoftDelUser("user1");
user1.getRoles().add(role1);
user1.getRoles().add(role2);
Ebean.save(user1);
LoggedSqlCollector.start();
Ebean.delete(user1);
List<String> loggedSql = LoggedSqlCollector.stop();
// No Delete from the relationship table
assertThat(loggedSql).hasSize(1);
assertThat(loggedSql.get(0)).contains("update esoft_del_user set version=?, deleted=? where id=? and version=?;");
}
}