- * {@link DatabaseConfig#setUpdatesDeleteMissingChildren(boolean)}: When cascade saving to a
- * OneToMany or ManyToMany the updatesDeleteMissingChildren setting controls if any other children
- * that are in the database but are not in the collection are deleted.
- *
- *
- * {@link DatabaseConfig#setUpdateChangesOnly(boolean)}: The updateChangesOnly setting
- * controls if only the changed properties are included in the update or if all the loaded
- * properties are included instead.
- *
*
{@code
*
* // A 'stateless update' example
@@ -414,9 +405,6 @@ public class DB {
* database.update(customer);
*
* }
- *
- * @see DatabaseConfig#setUpdatesDeleteMissingChildren(boolean)
- * @see DatabaseConfig#setUpdateChangesOnly(boolean)
*/
public static void update(Object bean) throws OptimisticLockException {
getDefault().update(bean);
diff --git a/src/main/java/io/ebean/Database.java b/src/main/java/io/ebean/Database.java
index ee9ece29d..25d6e6480 100644
--- a/src/main/java/io/ebean/Database.java
+++ b/src/main/java/io/ebean/Database.java
@@ -1216,9 +1216,6 @@ public interface Database {
* database.update(customer);
*
* }
- *
- * @see ServerConfig#setUpdatesDeleteMissingChildren(boolean)
- * @see ServerConfig#setUpdateChangesOnly(boolean)
*/
void update(Object bean) throws OptimisticLockException;
@@ -1227,16 +1224,6 @@ public interface Database {
*/
void update(Object bean, Transaction transaction) throws OptimisticLockException;
- /**
- * Update a bean additionally specifying a transaction and the deleteMissingChildren setting.
- *
- * @param bean the bean to update
- * @param transaction the transaction to use (can be null).
- * @param deleteMissingChildren specify false if you do not want 'missing children' of a OneToMany
- * or ManyToMany to be automatically deleted.
- */
- void update(Object bean, Transaction transaction, boolean deleteMissingChildren) throws OptimisticLockException;
-
/**
* Update a collection of beans. If there is no current transaction one is created and used to
* update all the beans in the collection.
diff --git a/src/main/java/io/ebean/config/ServerConfig.java b/src/main/java/io/ebean/config/ServerConfig.java
index e8534e30e..43fda49a1 100644
--- a/src/main/java/io/ebean/config/ServerConfig.java
+++ b/src/main/java/io/ebean/config/ServerConfig.java
@@ -355,11 +355,6 @@ public class ServerConfig {
*/
private boolean updateAllPropertiesInBatch;
- /**
- * Default behaviour for updates when cascade save on a O2M or M2M to delete any missing children.
- */
- private boolean updatesDeleteMissingChildren = true;
-
/**
* Database platform configuration.
*/
@@ -2423,22 +2418,6 @@ public class ServerConfig {
this.updateAllPropertiesInBatch = updateAllPropertiesInBatch;
}
- /**
- * Return true if updates by default delete missing children when cascading save to a OneToMany or
- * ManyToMany. When not set this defaults to true.
- */
- public boolean isUpdatesDeleteMissingChildren() {
- return updatesDeleteMissingChildren;
- }
-
- /**
- * Set if updates by default delete missing children when cascading save to a OneToMany or
- * ManyToMany. When not set this defaults to true.
- */
- public void setUpdatesDeleteMissingChildren(boolean updatesDeleteMissingChildren) {
- this.updatesDeleteMissingChildren = updatesDeleteMissingChildren;
- }
-
/**
* Return true if query statistics should be collected by ObjectGraphNode.
*/
@@ -2948,9 +2927,6 @@ public class ServerConfig {
skipCacheAfterWrite = p.getBoolean("skipCacheAfterWrite", skipCacheAfterWrite);
updateAllPropertiesInBatch = p.getBoolean("updateAllPropertiesInBatch", updateAllPropertiesInBatch);
- boolean defaultDeleteMissingChildren = p.getBoolean("defaultDeleteMissingChildren", updatesDeleteMissingChildren);
- updatesDeleteMissingChildren = p.getBoolean("updatesDeleteMissingChildren", defaultDeleteMissingChildren);
-
if (p.get("batch.mode") != null || p.get("persistBatching") != null) {
throw new IllegalArgumentException("Property 'batch.mode' or 'persistBatching' is being set but no longer used. Please change to use 'persistBatchMode'");
}
diff --git a/src/main/java/io/ebeaninternal/server/core/DefaultServer.java b/src/main/java/io/ebeaninternal/server/core/DefaultServer.java
index 87adc2066..04ce0a268 100644
--- a/src/main/java/io/ebeaninternal/server/core/DefaultServer.java
+++ b/src/main/java/io/ebeaninternal/server/core/DefaultServer.java
@@ -1736,30 +1736,16 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
((EntityBean) bean)._ebean_getIntercept().setDirty(true);
}
- /**
- * Update the bean using the default 'updatesDeleteMissingChildren' setting.
- */
@Override
public void update(Object bean) {
update(bean, null);
}
- /**
- * Update the bean using the default 'updatesDeleteMissingChildren' setting.
- */
@Override
public void update(Object bean, Transaction t) {
persister.update(checkEntityBean(bean), t);
}
- /**
- * Update the bean specifying the deleteMissingChildren option.
- */
- @Override
- public void update(Object bean, Transaction t, boolean deleteMissingChildren) {
- persister.update(checkEntityBean(bean), t, deleteMissingChildren);
- }
-
@Override
public void updateAll(Collection> beans) throws OptimisticLockException {
updateAll(beans, null);
diff --git a/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java b/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java
index b892f21c3..67cdc9324 100644
--- a/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java
+++ b/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java
@@ -104,8 +104,6 @@ public final class PersistRequestBean extends PersistRequest implements BeanP
private boolean notifyCache;
- private boolean deleteMissingChildren;
-
/**
* Flag used to detect when only many properties where updated via a cascade. Used to ensure
* appropriate caches are updated in that case.
@@ -629,20 +627,6 @@ public final class PersistRequestBean extends PersistRequest implements BeanP
return beanDescriptor;
}
- /**
- * Return true if a stateless update should also delete any missing details beans.
- */
- public boolean isDeleteMissingChildren() {
- return deleteMissingChildren;
- }
-
- /**
- * Set if deleteMissingChildren occurs on cascade save to OneToMany or ManyToMany.
- */
- public void setDeleteMissingChildren(boolean deleteMissingChildren) {
- this.deleteMissingChildren = deleteMissingChildren;
- }
-
/**
* Prepare the update after potential modifications in a BeanPersistController.
*/
@@ -1476,4 +1460,8 @@ public final class PersistRequestBean extends PersistRequest implements BeanP
}
this.saveManyIntersections.add(saveManyIntersection);
}
+
+ public boolean isForcedUpdate() {
+ return Flags.isUpdateForce(flags);
+ }
}
diff --git a/src/main/java/io/ebeaninternal/server/core/Persister.java b/src/main/java/io/ebeaninternal/server/core/Persister.java
index a0bdf1bb5..2bcda4b88 100644
--- a/src/main/java/io/ebeaninternal/server/core/Persister.java
+++ b/src/main/java/io/ebeaninternal/server/core/Persister.java
@@ -30,11 +30,6 @@ public interface Persister {
*/
void update(EntityBean entityBean, Transaction t);
- /**
- * Update the bean specifying deleteMissingChildren.
- */
- void update(EntityBean entityBean, Transaction t, boolean deleteMissingChildren);
-
/**
* Force an Insert using the given bean.
*/
diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java
index f884bb900..353fc5195 100644
--- a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java
+++ b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java
@@ -49,6 +49,7 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc implements ST
private final TableJoin intersectionJoin;
private final String intersectionPublishTable;
private final String intersectionDraftTable;
+ private final boolean orphanRemoval;
private IntersectionTable intersectionTable;
@@ -123,6 +124,7 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc implements ST
public BeanPropertyAssocMany(BeanDescriptor> descriptor, DeployBeanPropertyAssocMany deploy) {
super(descriptor, deploy);
this.unidirectional = deploy.isUnidirectional();
+ this.orphanRemoval = deploy.isOrphanRemoval();
this.o2mJoinTable = deploy.isO2mJoinTable();
this.hasOrderColumn = deploy.hasOrderColumn();
this.manyToMany = deploy.isManyToMany();
@@ -510,6 +512,10 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc implements ST
return hasOrderColumn;
}
+ public boolean isOrphanRemoval() {
+ return orphanRemoval;
+ }
+
@Override
public boolean isAssocMany() {
return true;
diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java
index 718a2d23b..aa41e95ab 100644
--- a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java
+++ b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java
@@ -39,11 +39,8 @@ import java.util.Map;
public class BeanPropertyAssocOne extends BeanPropertyAssoc implements STreePropertyAssocOne {
private final boolean oneToOne;
-
private final boolean oneToOneExported;
-
private final boolean orphanRemoval;
-
private final boolean primaryKeyExport;
private final boolean primaryKeyJoin;
@@ -89,7 +86,6 @@ public class BeanPropertyAssocOne extends BeanPropertyAssoc implements STr
for (BeanProperty embeddedProp : embeddedProps) {
embeddedPropsMap.put(embeddedProp.getName(), embeddedProp);
}
-
} else {
embeddedProps = null;
embeddedPropsMap = null;
diff --git a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssoc.java b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssoc.java
index bd2ccc6be..a7e060004 100644
--- a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssoc.java
+++ b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssoc.java
@@ -45,6 +45,8 @@ public abstract class DeployBeanPropertyAssoc extends DeployBeanProperty {
private PropertyForeignKey foreignKey;
+ boolean orphanRemoval;
+
/**
* Construct the property.
*/
@@ -148,6 +150,14 @@ public abstract class DeployBeanPropertyAssoc extends DeployBeanProperty {
}
}
+ public void setOrphanRemoval() {
+ orphanRemoval = true;
+ }
+
+ public boolean isOrphanRemoval() {
+ return orphanRemoval;
+ }
+
/**
* Set DocStoreEmbedded deployment information.
*/
diff --git a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocOne.java b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocOne.java
index 4dd42a503..79f253b86 100644
--- a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocOne.java
+++ b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocOne.java
@@ -21,8 +21,6 @@ public class DeployBeanPropertyAssocOne extends DeployBeanPropertyAssoc {
private String columnPrefix;
- private boolean orphanRemoval;
-
/**
* Create the property.
*/
@@ -145,14 +143,6 @@ public class DeployBeanPropertyAssocOne extends DeployBeanPropertyAssoc {
}
}
- public void setOrphanRemoval(boolean orphanRemoval) {
- this.orphanRemoval = orphanRemoval;
- }
-
- public boolean isOrphanRemoval() {
- return orphanRemoval;
- }
-
public void setJoinType(boolean outerJoin) {
tableJoin.setType(outerJoin ? SqlJoinType.OUTER : SqlJoinType.INNER);
}
diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java
index 3550fc192..55640603b 100644
--- a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java
+++ b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java
@@ -84,11 +84,13 @@ class AnnotationAssocManys extends AnnotationParser {
if (oneToMany != null) {
readToOne(oneToMany, prop);
if (readOrphanRemoval(oneToMany)) {
+ prop.setOrphanRemoval();
prop.setModifyListenMode(ModifyListenMode.REMOVALS);
prop.getCascadeInfo().setDelete(true);
}
PrivateOwned privateOwned = get(prop, PrivateOwned.class);
if (privateOwned != null) {
+ prop.setOrphanRemoval();
prop.setModifyListenMode(ModifyListenMode.REMOVALS);
prop.getCascadeInfo().setDelete(privateOwned.cascadeRemove());
}
diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java
index dda924752..4e2084100 100644
--- a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java
+++ b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java
@@ -225,7 +225,9 @@ public class AnnotationAssocOnes extends AnnotationParser {
prop.setNullable(propAnn.optional());
prop.setFetchType(propAnn.fetch());
prop.setMappedBy(propAnn.mappedBy());
- prop.setOrphanRemoval(readOrphanRemoval(propAnn));
+ if (readOrphanRemoval(propAnn)) {
+ prop.setOrphanRemoval();
+ }
if (!"".equals(propAnn.mappedBy())) {
prop.setOneToOneExported();
}
diff --git a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java
index e3a93cfad..24541a636 100644
--- a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java
+++ b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java
@@ -74,11 +74,8 @@ public final class DefaultPersister implements Persister {
private final BeanDescriptorManager beanDescriptorManager;
- private final boolean updatesDeleteMissingChildren;
-
public DefaultPersister(SpiEbeanServer server, Binder binder, BeanDescriptorManager descMgr) {
this.server = server;
- this.updatesDeleteMissingChildren = server.getServerConfig().isUpdatesDeleteMissingChildren();
this.beanDescriptorManager = descMgr;
this.persistExecute = new DefaultPersistExecute(binder, server.getServerConfig().getPersistBatchSize());
}
@@ -407,17 +404,7 @@ public final class DefaultPersister implements Persister {
*/
@Override
public void update(EntityBean entityBean, Transaction t) {
- update(entityBean, t, updatesDeleteMissingChildren);
- }
-
- /**
- * Update the bean specifying deleteMissingChildren.
- */
- @Override
- public void update(EntityBean entityBean, Transaction t, boolean deleteMissingChildren) {
-
PersistRequestBean> req = createRequest(entityBean, t, PersistRequest.Type.UPDATE);
- req.setDeleteMissingChildren(deleteMissingChildren);
req.checkDraft();
try {
req.initTransIfRequiredWithBatchCascade();
@@ -448,8 +435,7 @@ public final class DefaultPersister implements Persister {
@Override
public void save(EntityBean bean, Transaction t) {
if (bean._ebean_getIntercept().isUpdate()) {
- // deleteMissingChildren is false when using 'save' on 'loaded' beans
- update(bean, t, false);
+ update(bean, t);
} else {
insert(bean, t);
}
diff --git a/src/main/java/io/ebeaninternal/server/persist/Flags.java b/src/main/java/io/ebeaninternal/server/persist/Flags.java
index 0d9a9ccf9..6c200911e 100644
--- a/src/main/java/io/ebeaninternal/server/persist/Flags.java
+++ b/src/main/java/io/ebeaninternal/server/persist/Flags.java
@@ -78,6 +78,10 @@ public final class Flags {
return (state & PUBLISH_MERGE_NORMAL) != 0;
}
+ public static boolean isUpdateForce(int state) {
+ return !isSet(state, INSERT) && !isSet(state, NORMAL);
+ }
+
/**
* Return true if the given flag is set.
*/
@@ -149,10 +153,10 @@ public final class Flags {
}
private static int set(int state, int flag) {
- return (state |= flag);
+ return state | flag;
}
private static int unset(int state, int flag) {
- return state &= ~flag;
+ return state & ~flag;
}
}
diff --git a/src/main/java/io/ebeaninternal/server/persist/SaveManyBeans.java b/src/main/java/io/ebeaninternal/server/persist/SaveManyBeans.java
index afbf394cd..883947439 100644
--- a/src/main/java/io/ebeaninternal/server/persist/SaveManyBeans.java
+++ b/src/main/java/io/ebeaninternal/server/persist/SaveManyBeans.java
@@ -38,7 +38,6 @@ public class SaveManyBeans extends SaveManyBase {
private Collection> collection;
private final DefaultPersister persister;
- private boolean deleteMissing;
private int sortOrder;
SaveManyBeans(boolean insertedParent, BeanPropertyAssocMany> many, EntityBean parentBean, PersistRequestBean> request, DefaultPersister persister) {
@@ -56,18 +55,17 @@ public class SaveManyBeans extends SaveManyBase {
void save() {
if (many.hasJoinTable()) {
-
// check if we can save the m2m intersection in this direction
// we only allow one direction based on first traversed basis
boolean saveIntersectionFromThisDirection = isSaveIntersection();
if (cascade) {
- saveAssocManyDetails(false);
+ saveAssocManyDetails();
}
// for ManyToMany save the 'relationship' via inserts/deletes
// into/from the intersection table
if (saveIntersectionFromThisDirection) {
// only allowed on one direction of a m2m based on beanName
- saveAssocManyIntersection(request.isDeleteMissingChildren());
+ saveAssocManyIntersection();
} else {
resetModifyState();
}
@@ -79,7 +77,7 @@ public class SaveManyBeans extends SaveManyBase {
}
if (cascade) {
// potentially deletes 'missing children' for 'stateless update'
- saveAssocManyDetails(request.isDeleteMissingChildren());
+ saveAssocManyDetails();
}
}
}
@@ -98,13 +96,9 @@ public class SaveManyBeans extends SaveManyBase {
/**
* Save the details from a OneToMany collection.
*/
- private void saveAssocManyDetails(boolean deleteMissingChildren) {
-
- this.deleteMissing = deleteMissingChildren;
-
+ private void saveAssocManyDetails() {
// check that the list is not null and if it is a BeanCollection
// check that is has been populated (don't trigger lazy loading)
-
collection = BeanCollectionUtil.getActualEntries(value);
if (collection != null) {
processDetails();
@@ -127,7 +121,7 @@ public class SaveManyBeans extends SaveManyBase {
targetDescriptor.preAllocateIds(collection.size());
}
- if (deleteMissing) {
+ if (!insertedParent && many.isOrphanRemoval() && request.isForcedUpdate()) {
// collect the Id's (to exclude from deleteManyDetails)
List