diff --git a/src/main/java/com/avaje/ebean/Ebean.java b/src/main/java/com/avaje/ebean/Ebean.java
index c478e90fe..1255f3a2c 100644
--- a/src/main/java/com/avaje/ebean/Ebean.java
+++ b/src/main/java/com/avaje/ebean/Ebean.java
@@ -704,6 +704,10 @@ public final class Ebean {
* you automatically.
*
*
+ * If the bean is configured with @SoftDelete then this will perform a soft
+ * delete rather than a hard/permanent delete.
+ *
+ *
* If the Bean does not have a version property (or loaded version property) and
* the bean does not exist then this returns false indicating that nothing was
* deleted. Note that, if JDBC batch mode is used then this always returns true.
@@ -713,6 +717,13 @@ public final class Ebean {
return serverMgr.getDefaultServer().delete(bean);
}
+ /**
+ * Delete the bean in permanent fashion (will not use soft delete).
+ */
+ public static boolean deletePermanent(Object bean) throws OptimisticLockException {
+ return serverMgr.getDefaultServer().deletePermanent(bean);
+ }
+
/**
* Delete the bean given its type and id.
*/
@@ -734,6 +745,13 @@ public final class Ebean {
return serverMgr.getDefaultServer().deleteAll(beans);
}
+ /**
+ * Delete permanent all the beans in the Collection (will not use soft delete).
+ */
+ public static int deleteAllPermanent(Collection> beans) throws OptimisticLockException {
+ return serverMgr.getDefaultServer().deleteAllPermanent(beans);
+ }
+
/**
* Refresh the values of a bean.
*
diff --git a/src/main/java/com/avaje/ebean/EbeanServer.java b/src/main/java/com/avaje/ebean/EbeanServer.java
index 1f8b809dd..459ab6b4d 100644
--- a/src/main/java/com/avaje/ebean/EbeanServer.java
+++ b/src/main/java/com/avaje/ebean/EbeanServer.java
@@ -1273,6 +1273,26 @@ public interface EbeanServer {
*/
boolean delete(Object bean, Transaction transaction) throws OptimisticLockException;
+ /**
+ * Delete a bean permanently without soft delete.
+ */
+ boolean deletePermanent(Object bean) throws OptimisticLockException;
+
+ /**
+ * Delete a bean permanently without soft delete using an explicit transaction.
+ */
+ boolean deletePermanent(Object bean, Transaction transaction) throws OptimisticLockException;
+
+ /**
+ * Delete all the beans in the collection permanently without soft delete.
+ */
+ int deleteAllPermanent(Collection> beans) throws OptimisticLockException;
+
+ /**
+ * Delete all the beans in the collection permanently without soft delete using an explicit transaction.
+ */
+ int deleteAllPermanent(Collection> beans, Transaction transaction) throws OptimisticLockException;
+
/**
* Delete the bean given its type and id.
*/
diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java
index d9ec8164c..3b0421ec6 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java
@@ -1883,9 +1883,28 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
/**
* Delete the bean with the explicit transaction.
*/
- public boolean delete(Object bean, Transaction t) {
-
- return persister.delete(checkEntityBean(bean), t);
+ public boolean delete(Object bean, Transaction t) throws OptimisticLockException {
+ return persister.delete(checkEntityBean(bean), t, false);
+ }
+
+ @Override
+ public boolean deletePermanent(Object bean) throws OptimisticLockException {
+ return deletePermanent(bean, null);
+ }
+
+ @Override
+ public boolean deletePermanent(Object bean, Transaction t) throws OptimisticLockException {
+ return persister.delete(checkEntityBean(bean), t, true);
+ }
+
+ @Override
+ public int deleteAllPermanent(Collection> beans) {
+ return deleteAllInternal(beans.iterator(), null, true);
+ }
+
+ @Override
+ public int deleteAllPermanent(Collection> beans, Transaction t) {
+ return deleteAllInternal(beans.iterator(), t, true);
}
/**
@@ -1893,7 +1912,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
*/
@Override
public int deleteAll(Collection> beans) {
- return deleteAllInternal(beans.iterator(), null);
+ return deleteAllInternal(beans.iterator(), null, false);
}
/**
@@ -1901,13 +1920,13 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
*/
@Override
public int deleteAll(Collection> beans, Transaction t) {
- return deleteAllInternal(beans.iterator(), t);
+ return deleteAllInternal(beans.iterator(), t, false);
}
/**
* Delete all the beans in the iterator with an explicit transaction.
*/
- private int deleteAllInternal(Iterator> it, Transaction t) {
+ private int deleteAllInternal(Iterator> it, Transaction t, boolean permanent) {
TransWrapper wrap = initTransIfRequired(t);
@@ -1917,7 +1936,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
int deleteCount = 0;
while (it.hasNext()) {
EntityBean bean = checkEntityBean(it.next());
- persister.delete(bean, trans);
+ persister.delete(bean, trans, permanent);
deleteCount++;
}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequest.java b/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequest.java
index 0d1eeb9ae..faa8d432b 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequest.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequest.java
@@ -12,7 +12,7 @@ import com.avaje.ebeaninternal.server.persist.PersistExecute;
public abstract class PersistRequest extends BeanRequest implements BatchPostExecute {
public enum Type {
- INSERT, UPDATE, DELETE, SOFT_DELETE, UPDATESQL, CALLABLESQL
+ INSERT, UPDATE, DELETE, SOFT_DELETE, DELETE_PERMANENT, UPDATESQL, CALLABLESQL
}
protected boolean persistCascade;
diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestBean.java b/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestBean.java
index 00b69ba60..ceb1f211d 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestBean.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestBean.java
@@ -256,6 +256,7 @@ public final class PersistRequestBean extends PersistRequest implements BeanP
beanDescriptor.cacheHandleUpdate(idValue, this);
break;
case DELETE:
+ case SOFT_DELETE:
// Bean deleted from cache early via postDelete()
break;
default:
@@ -546,6 +547,7 @@ public final class PersistRequestBean extends PersistRequest implements BeanP
}
switch (type) {
case DELETE:
+ case SOFT_DELETE:
postDelete();
break;
case UPDATE:
@@ -614,6 +616,7 @@ public final class PersistRequestBean extends PersistRequest implements BeanP
controller.postUpdate(this);
break;
case DELETE:
+ case SOFT_DELETE:
controller.postDelete(this);
break;
default:
@@ -635,6 +638,9 @@ public final class PersistRequestBean extends PersistRequest implements BeanP
case DELETE:
transaction.logSummary("Deleted [" + name + "] [" + idValue + "]" + draft);
break;
+ case SOFT_DELETE:
+ transaction.logSummary("SoftDelete [" + name + "] [" + idValue + "]" + draft);
+ break;
default:
break;
}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/Persister.java b/src/main/java/com/avaje/ebeaninternal/server/core/Persister.java
index df79b7ae2..fac5f767b 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/core/Persister.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/core/Persister.java
@@ -66,7 +66,7 @@ public interface Persister {
/**
* Delete the bean.
*/
- boolean delete(EntityBean entityBean, Transaction t);
+ boolean delete(EntityBean entityBean, Transaction t, boolean permanent);
/**
* Delete multiple beans given a collection of Id values.
diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptor.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptor.java
index 30fc2d8ac..991ad293c 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptor.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptor.java
@@ -683,6 +683,7 @@ public class BeanDescriptor implements MetaBeanInfo, SpiBeanType {
case INSERT:
return changeLogFilter.includeInsert(request) ? insertBeanChange(request): null;
case UPDATE:
+ case SOFT_DELETE:
return changeLogFilter.includeUpdate(request) ? updateBeanChange(request): null;
case DELETE:
return changeLogFilter.includeDelete(request) ? deleteBeanChange(request) :null;
diff --git a/src/main/java/com/avaje/ebeaninternal/server/persist/BatchedBeanHolder.java b/src/main/java/com/avaje/ebeaninternal/server/persist/BatchedBeanHolder.java
index 7e761ce47..df18d3a93 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/persist/BatchedBeanHolder.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/persist/BatchedBeanHolder.java
@@ -138,6 +138,7 @@ public class BatchedBeanHolder {
return inserts.size();
case UPDATE:
+ case SOFT_DELETE:
if (updates == null) {
updates = new ArrayList();
}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/persist/DefaultPersister.java b/src/main/java/com/avaje/ebeaninternal/server/persist/DefaultPersister.java
index 711147526..46d3e476a 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/persist/DefaultPersister.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/persist/DefaultPersister.java
@@ -336,7 +336,7 @@ public final class DefaultPersister implements Persister {
*/
private void deleteRecurse(EntityBean detailBean, Transaction t, boolean softDelete) {
- Type deleteType = softDelete ? Type.SOFT_DELETE : Type.DELETE;
+ Type deleteType = softDelete ? Type.SOFT_DELETE : Type.DELETE_PERMANENT;
deleteRequest(createRequest(detailBean, t, deleteType));
}
@@ -498,15 +498,16 @@ public final class DefaultPersister implements Persister {
* Delete the bean with the explicit transaction.
* Return false if the delete is executed without OCC and 0 rows were deleted.
*/
- public boolean delete(EntityBean bean, Transaction t) {
+ public boolean delete(EntityBean bean, Transaction t, boolean permanent) {
- PersistRequestBean request = createRequest(bean, t, Type.DELETE);
+ Type deleteType = permanent ? Type.DELETE_PERMANENT : Type.DELETE;
+ PersistRequestBean request = createRequest(bean, t, deleteType);
boolean deleted = deleteRequest(request);
- if (request.isDraftable()) {
+ if (request.isDraftable() && request.getType() == Type.DELETE) {
// we have just deleting a draft bean so now we need to delete the
// associated 'live' bean. This is effectively an 'automatic publish'.
- deleteRequest(createPublishRequest(request.createReference(), t, Type.DELETE, true));
+ deleteRequest(createPublishRequest(request.createReference(), t, Type.DELETE_PERMANENT, true));
}
return deleted;
}
@@ -541,8 +542,8 @@ public final class DefaultPersister implements Persister {
private void deleteList(List> beanList, Transaction t, boolean softDelete) {
for (int i = 0; i < beanList.size(); i++) {
-// deleteRecurse((EntityBean) beanList.get(i), t, softDelete);
- delete((EntityBean) beanList.get(i), t);
+ deleteRecurse((EntityBean) beanList.get(i), t, softDelete);
+ //delete((EntityBean) beanList.get(i), t);
}
}
@@ -590,7 +591,7 @@ public final class DefaultPersister implements Persister {
// We actually need to execute a query to get the foreign key values
// as they are required for the delete cascade. Query back just the
// Id and the appropriate foreign key values
- Query> q = deleteRequiresQuery(descriptor, propImportDelete);
+ Query> q = deleteRequiresQuery(descriptor, propImportDelete, softDelete);
if (idList != null) {
q.where().idIn(idList);
if (t.isLogSummary()) {
@@ -701,7 +702,7 @@ public final class DefaultPersister implements Persister {
* We need to create and execute a query to get the foreign key values as
* the delete cascades to them (foreign keys).
*/
- private Query> deleteRequiresQuery(BeanDescriptor> desc, BeanPropertyAssocOne>[] propImportDelete) {
+ private Query> deleteRequiresQuery(BeanDescriptor> desc, BeanPropertyAssocOne>[] propImportDelete, boolean softDelete) {
Query> q = server.createQuery(desc.getBeanType());
StringBuilder sb = new StringBuilder(30);
@@ -710,6 +711,10 @@ public final class DefaultPersister implements Persister {
}
q.setAutoTune(false);
q.select(sb.toString());
+ if (!softDelete) {
+ // hard delete so we want this query to include logically deleted rows (if any)
+ q.includeSoftDeletes();
+ }
return q;
}
@@ -1492,7 +1497,10 @@ public final class DefaultPersister implements Persister {
private PersistRequestBean createRequest(T bean, Transaction t, Object parentBean, BeanManager> mgr,
PersistRequest.Type type, boolean saveRecurse, boolean publish) {
- if (type == Type.DELETE && mgr.getBeanDescriptor().isSoftDelete()) {
+ if (type == Type.DELETE_PERMANENT) {
+ type = Type.DELETE;
+ } else if (type == Type.DELETE && mgr.getBeanDescriptor().isSoftDelete()) {
+ // automatically convert to soft delete for types that support it
type = Type.SOFT_DELETE;
}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/transaction/BeanPersistIds.java b/src/main/java/com/avaje/ebeaninternal/server/transaction/BeanPersistIds.java
index 6ef1bdf20..f44dfdefc 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/transaction/BeanPersistIds.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/transaction/BeanPersistIds.java
@@ -183,6 +183,7 @@ public class BeanPersistIds implements Serializable {
addUpdateId(id);
break;
case DELETE:
+ case SOFT_DELETE:
addDeleteId(id);
break;
diff --git a/src/test/java/com/avaje/ebeaninternal/api/TDSpiEbeanServer.java b/src/test/java/com/avaje/ebeaninternal/api/TDSpiEbeanServer.java
index 467d416b0..172601c66 100644
--- a/src/test/java/com/avaje/ebeaninternal/api/TDSpiEbeanServer.java
+++ b/src/test/java/com/avaje/ebeaninternal/api/TDSpiEbeanServer.java
@@ -667,6 +667,26 @@ public class TDSpiEbeanServer implements SpiEbeanServer {
return false;
}
+ @Override
+ public boolean deletePermanent(Object bean) throws OptimisticLockException {
+ return false;
+ }
+
+ @Override
+ public boolean deletePermanent(Object bean, Transaction transaction) throws OptimisticLockException {
+ return false;
+ }
+
+ @Override
+ public int deleteAllPermanent(Collection> beans) throws OptimisticLockException {
+ return 0;
+ }
+
+ @Override
+ public int deleteAllPermanent(Collection> beans, Transaction transaction) throws OptimisticLockException {
+ return 0;
+ }
+
@Override
public int execute(SqlUpdate updSql, Transaction t) {
return 0;
diff --git a/src/test/java/com/avaje/tests/model/softdelete/ESoftDelDown.java b/src/test/java/com/avaje/tests/model/softdelete/ESoftDelDown.java
new file mode 100644
index 000000000..ac36bd71e
--- /dev/null
+++ b/src/test/java/com/avaje/tests/model/softdelete/ESoftDelDown.java
@@ -0,0 +1,21 @@
+package com.avaje.tests.model.softdelete;
+
+import javax.persistence.Entity;
+
+@Entity
+public class ESoftDelDown extends BaseSoftDelete {
+
+ String down;
+
+ public ESoftDelDown(String up) {
+ this.down = down;
+ }
+
+ public String getDown() {
+ return down;
+ }
+
+ public void setDown(String down) {
+ this.down = down;
+ }
+}
diff --git a/src/test/java/com/avaje/tests/model/softdelete/ESoftDelMid.java b/src/test/java/com/avaje/tests/model/softdelete/ESoftDelMid.java
new file mode 100644
index 000000000..499d33e40
--- /dev/null
+++ b/src/test/java/com/avaje/tests/model/softdelete/ESoftDelMid.java
@@ -0,0 +1,64 @@
+package com.avaje.tests.model.softdelete;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import javax.persistence.ManyToMany;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import java.util.List;
+
+@Entity
+public class ESoftDelMid extends BaseSoftDelete {
+
+ @ManyToOne(optional = false)
+ ESoftDelTop top;
+
+ String mid;
+
+ @ManyToOne(cascade = CascadeType.ALL)
+ ESoftDelUp up;
+
+ @OneToMany(cascade = CascadeType.ALL)
+ List downs;
+
+ public ESoftDelMid(ESoftDelTop top, String mid) {
+ this.top = top;
+ this.mid = mid;
+ }
+
+ public ESoftDelTop getTop() {
+ return top;
+ }
+
+ public void setTop(ESoftDelTop top) {
+ this.top = top;
+ }
+
+ public ESoftDelUp getUp() {
+ return up;
+ }
+
+ public void setUp(ESoftDelUp up) {
+ this.up = up;
+ }
+
+ public String getMid() {
+ return mid;
+ }
+
+ public void setMid(String mid) {
+ this.mid = mid;
+ }
+
+ public List getDowns() {
+ return downs;
+ }
+
+ public void setDowns(List downs) {
+ this.downs = downs;
+ }
+
+ public void addDown(String down) {
+ getDowns().add(new ESoftDelDown(down));
+ }
+}
diff --git a/src/test/java/com/avaje/tests/model/softdelete/ESoftDelTop.java b/src/test/java/com/avaje/tests/model/softdelete/ESoftDelTop.java
new file mode 100644
index 000000000..d17b6ec30
--- /dev/null
+++ b/src/test/java/com/avaje/tests/model/softdelete/ESoftDelTop.java
@@ -0,0 +1,44 @@
+package com.avaje.tests.model.softdelete;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import javax.persistence.ManyToMany;
+import javax.persistence.OneToMany;
+import java.util.List;
+
+@Entity
+public class ESoftDelTop extends BaseSoftDelete {
+
+ String top;
+
+ @OneToMany(mappedBy = "top", cascade = CascadeType.ALL)
+ List mids;
+
+ public ESoftDelTop(String top) {
+ this.top = top;
+ }
+
+ public String getTop() {
+ return top;
+ }
+
+ public void setTop(String top) {
+ this.top = top;
+ }
+
+ public List getMids() {
+ return mids;
+ }
+
+ public void setMids(List mids) {
+ this.mids = mids;
+ }
+
+ public ESoftDelMid addMids(String mid) {
+
+ ESoftDelMid bean = new ESoftDelMid(this, mid);
+ getMids().add(bean);
+ return bean;
+ }
+
+}
diff --git a/src/test/java/com/avaje/tests/model/softdelete/ESoftDelUp.java b/src/test/java/com/avaje/tests/model/softdelete/ESoftDelUp.java
new file mode 100644
index 000000000..f53a2215b
--- /dev/null
+++ b/src/test/java/com/avaje/tests/model/softdelete/ESoftDelUp.java
@@ -0,0 +1,21 @@
+package com.avaje.tests.model.softdelete;
+
+import javax.persistence.Entity;
+
+@Entity
+public class ESoftDelUp extends BaseSoftDelete {
+
+ String up;
+
+ public ESoftDelUp(String up) {
+ this.up = up;
+ }
+
+ public String getUp() {
+ return up;
+ }
+
+ public void setUp(String up) {
+ this.up = up;
+ }
+}
diff --git a/src/test/java/com/avaje/tests/softdelete/TestSoftDeleteBasic.java b/src/test/java/com/avaje/tests/softdelete/TestSoftDeleteBasic.java
index 4954ac54d..fe9133196 100644
--- a/src/test/java/com/avaje/tests/softdelete/TestSoftDeleteBasic.java
+++ b/src/test/java/com/avaje/tests/softdelete/TestSoftDeleteBasic.java
@@ -20,7 +20,6 @@ public class TestSoftDeleteBasic extends BaseTestCase {
EBasicSoftDelete bean = new EBasicSoftDelete();
bean.setName("one");
-
Ebean.save(bean);
Ebean.delete(bean);
@@ -42,7 +41,39 @@ public class TestSoftDeleteBasic extends BaseTestCase {
.findUnique();
assertThat(findInclude).isNotNull();
+ }
+ @Test
+ public void testDeleteById() {
+
+ EBasicSoftDelete bean = new EBasicSoftDelete();
+ bean.setName("two");
+ Ebean.save(bean);
+
+ Ebean.delete(EBasicSoftDelete.class, bean.getId());
+ }
+
+ @Test
+ public void testDeletePartial() {
+
+ EBasicSoftDelete bean = new EBasicSoftDelete();
+ bean.setName("partial");
+ Ebean.save(bean);
+
+ // partially loaded bean without deleted state loaded
+ EBasicSoftDelete partial = Ebean.find(EBasicSoftDelete.class)
+ .select("id")
+ .setId(bean.getId())
+ .findUnique();
+
+ LoggedSqlCollector.start();
+ Ebean.delete(partial);
+
+ // check lazy loading isn't invoked (deleted set to true without invoking lazy loading)
+ List loggedSql = LoggedSqlCollector.stop();
+ assertThat(loggedSql).hasSize(2);
+ assertThat(loggedSql.get(0)).contains("update ebasic_sdchild set deleted=");
+ assertThat(loggedSql.get(1)).contains("update ebasic_soft_delete set deleted=? where id=?");
}
@Test
diff --git a/src/test/java/com/avaje/tests/softdelete/TestSoftDeleteTop.java b/src/test/java/com/avaje/tests/softdelete/TestSoftDeleteTop.java
new file mode 100644
index 000000000..ecbaa79a6
--- /dev/null
+++ b/src/test/java/com/avaje/tests/softdelete/TestSoftDeleteTop.java
@@ -0,0 +1,97 @@
+package com.avaje.tests.softdelete;
+
+import com.avaje.ebean.BaseTestCase;
+import com.avaje.ebean.Ebean;
+import com.avaje.ebean.Transaction;
+import com.avaje.ebean.config.PersistBatch;
+import com.avaje.tests.model.softdelete.ESoftDelMid;
+import com.avaje.tests.model.softdelete.ESoftDelRole;
+import com.avaje.tests.model.softdelete.ESoftDelTop;
+import com.avaje.tests.model.softdelete.ESoftDelUp;
+import com.avaje.tests.model.softdelete.ESoftDelUser;
+import org.avaje.ebeantest.LoggedSqlCollector;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class TestSoftDeleteTop extends BaseTestCase {
+
+ @Test
+ public void testDeletePermanent() {
+
+ ESoftDelUp up1 = new ESoftDelUp("up1");
+ Ebean.save(up1);
+
+ Ebean.delete(up1);
+ Ebean.deletePermanent(up1);
+ }
+
+
+ @Test
+ public void testSoftDeleteJdbcBatch() {
+
+ ESoftDelUp up1 = new ESoftDelUp("upBatch1");
+ Ebean.save(up1);
+ ESoftDelUp up2 = new ESoftDelUp("upBatch2");
+ Ebean.save(up2);
+
+ Transaction transaction = Ebean.beginTransaction();
+ try {
+ transaction.setBatch(PersistBatch.ALL);
+ Ebean.delete(up1);
+ Ebean.delete(up2);
+ transaction.commit();
+ } finally {
+ transaction.end();
+ }
+
+ List list = new ArrayList();
+ list.add(up1);
+ list.add(up2);
+
+ Ebean.deleteAllPermanent(list);
+ }
+
+ @Test
+ public void testSoftDeleteAll() {
+
+ ESoftDelUp up1 = new ESoftDelUp("upBatchX");
+ ESoftDelUp up2 = new ESoftDelUp("upBatchY");
+
+ List list = new ArrayList();
+ list.add(up1);
+ list.add(up2);
+
+ // by default uses JDBC for the 'all' methods
+ Ebean.saveAll(list);
+ Ebean.deleteAll(list);
+ Ebean.deleteAllPermanent(list);
+
+ }
+
+ @Test
+ public void test() {
+
+ ESoftDelUp up1 = new ESoftDelUp("up1");
+
+ ESoftDelTop top1 = new ESoftDelTop("top1");
+ ESoftDelMid mid1 = top1.addMids("mid1");
+ mid1.addDown("down1");
+ mid1.addDown("down2");
+ mid1.setUp(up1);
+
+ ESoftDelMid mid2 = top1.addMids("mid2");
+ mid2.addDown("down3");
+ mid2.addDown("down4");
+
+ Ebean.save(top1);
+
+ Ebean.delete(top1);
+
+ Ebean.deletePermanent(top1);
+ }
+
+}