diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransaction.java b/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransaction.java index 67d11c5921..5abaf9aa60 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransaction.java @@ -65,12 +65,12 @@ public interface SpiTransaction extends Transaction { *

* This is to handle bi-directional relationships where both sides Cascade. */ - void registerDeleteBean(Integer hash); + void registerDeleteBean(Class type, Object id); /** * Return true if this is a bean that has already been saved/deleted. */ - boolean isRegisteredDeleteBean(Integer hash); + boolean isRegisteredDeleteBean(Class type, Object id); /** * Unregister the persisted beans. Expected after persisting top level beans diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransactionProxy.java b/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransactionProxy.java index 7914796b09..b7d3aa05f6 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransactionProxy.java +++ b/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransactionProxy.java @@ -195,13 +195,13 @@ public void registerDeferred(PersistDeferredRelationship derived) { } @Override - public void registerDeleteBean(Integer hash) { - transaction.registerDeleteBean(hash); + public void registerDeleteBean(Class type, Object id) { + transaction.registerDeleteBean(type, id); } @Override - public boolean isRegisteredDeleteBean(Integer hash) { - return transaction.isRegisteredDeleteBean(hash); + public boolean isRegisteredDeleteBean(Class type, Object id) { + return transaction.isRegisteredDeleteBean(type, id); } @Override 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 93358d0c6d..ecbd8e5f8a 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 @@ -54,10 +54,6 @@ public final class PersistRequestBean extends PersistRequest implements BeanP * The unique id used for logging summary. */ private Object idValue; - /** - * Hash value used to handle cascade delete both ways in a relationship. - */ - private Integer beanHash; private boolean statelessUpdate; private boolean notifyCache; /** @@ -285,7 +281,9 @@ private void onUpdateGeneratedProperties() { private void onFailedUpdateUndoGeneratedProperties() { for (BeanProperty prop : beanDescriptor.propertiesGenUpdate()) { Object oldVal = intercept.origValue(prop.propertyIndex()); - prop.setValue(entityBean, oldVal); + if (oldVal != null) { + prop.setValue(entityBean, oldVal); + } } } @@ -553,34 +551,17 @@ public void unRegisterBean() { } } - /** - * The hash used to register the bean with the transaction. - *

- * Takes into account the class type and id value. - */ - private Integer beanHash() { - if (beanHash == null) { - Object id = beanDescriptor.getId(entityBean); - int hc = 92821 * bean.getClass().getName().hashCode(); - if (id != null) { - hc += id.hashCode(); - } - beanHash = hc; - } - return beanHash; - } - public void registerDeleteBean() { - Integer hash = beanHash(); - transaction.registerDeleteBean(hash); + final Object id = beanDescriptor.id(entityBean); + transaction.registerDeleteBean(beanDescriptor.type(), id); } public boolean isRegisteredForDeleteBean() { if (transaction == null) { return false; } else { - Integer hash = beanHash(); - return transaction.isRegisteredDeleteBean(hash); + final Object id = beanDescriptor.id(entityBean); + return transaction.isRegisteredDeleteBean(beanDescriptor.type(), id); } } @@ -809,7 +790,9 @@ public void setBoundId(Object idValue) { public void checkRowCount(int rowCount) { if (rowCount != 1 && rowCount != Statement.SUCCESS_NO_INFO) { if (ConcurrencyMode.VERSION == concurrencyMode) { - onFailedUpdateUndoGeneratedProperties(); + if (type == Type.UPDATE) { + onFailedUpdateUndoGeneratedProperties(); + } throw new OptimisticLockException("Data has changed. updated row count " + rowCount, null, bean); } else if (rowCount == 0 && type == Type.UPDATE) { throw new EntityNotFoundException("No rows updated"); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/ImplicitReadOnlyTransaction.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/ImplicitReadOnlyTransaction.java index 84c97f4198..3d091ff8f8 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/ImplicitReadOnlyTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/ImplicitReadOnlyTransaction.java @@ -200,7 +200,7 @@ public void registerDeferred(PersistDeferredRelationship derived) { } @Override - public void registerDeleteBean(Integer persistingBean) { + public void registerDeleteBean(Class type, Object id) { throw new IllegalStateException(notExpectedMessage); } @@ -208,7 +208,7 @@ public void registerDeleteBean(Integer persistingBean) { * Return true if this is a bean that has already been saved/deleted. */ @Override - public boolean isRegisteredDeleteBean(Integer persistingBean) { + public boolean isRegisteredDeleteBean(Class type, Object id) { return false; } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java index 38a4324a06..8396f20a43 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java @@ -68,7 +68,7 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { private int depth; private boolean autoCommit; private IdentityHashMap persistingBeans; - private HashSet deletingBeansHash; + private Map, Set> deletingBeans; private HashMap m2mIntersectionSave; private Map userObjects; private List callbackList; @@ -328,40 +328,28 @@ public final void registerDeferred(PersistDeferredRelationship derived) { deferredList.add(derived); } - /** - * Add a bean to the registed list. - *

- * This is to handle bi-directional relationships where both sides Cascade. - *

- */ @Override - public final void registerDeleteBean(Integer persistingBean) { - if (deletingBeansHash == null) { - deletingBeansHash = new HashSet<>(); - } - deletingBeansHash.add(persistingBean); + public final void registerDeleteBean(Class type, Object id) { + deleteBeanIds(type).add(id); } - /** - * Return true if this is a bean that has already been saved/deleted. - */ @Override - public final boolean isRegisteredDeleteBean(Integer persistingBean) { - return deletingBeansHash != null && deletingBeansHash.contains(persistingBean); + public final boolean isRegisteredDeleteBean(Class type, Object id) { + return deleteBeanIds(type).contains(id); + } + + private Set deleteBeanIds(Class type) { + if (deletingBeans == null) { + deletingBeans = new HashMap<>(); + } + return deletingBeans.computeIfAbsent(type, k -> new HashSet<>()); } - /** - * Unregister the persisted beans (when persisting at the top level). - */ @Override public final void unregisterBeans() { persistingBeans.clear(); } - /** - * Return true if this is a bean that has already been saved. This will - * register the bean if it is not already. - */ @Override public final boolean isRegisteredBean(Object bean) { if (persistingBeans == null) { @@ -370,10 +358,6 @@ public final boolean isRegisteredBean(Object bean) { return (persistingBeans.put(bean, PLACEHOLDER) != null); } - /** - * Return true if the m2m intersection save is allowed from a given bean direction. - * This is to stop m2m intersection management via both directions of a m2m. - */ @Override public final boolean isSaveAssocManyIntersection(String intersectionTable, String beanName) { if (m2mIntersectionSave == null) { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/NoTransaction.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/NoTransaction.java index c470688c87..9fd92ae150 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/NoTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/NoTransaction.java @@ -154,12 +154,12 @@ public void registerDeferred(PersistDeferredRelationship derived) { } @Override - public void registerDeleteBean(Integer hash) { + public void registerDeleteBean(Class type, Object id) { } @Override - public boolean isRegisteredDeleteBean(Integer hash) { + public boolean isRegisteredDeleteBean(Class type, Object id) { return false; } diff --git a/ebean-test/src/test/java/org/tests/iud/TestCarWheelIud.java b/ebean-test/src/test/java/org/tests/iud/TestCarWheelIud.java index b90c9cc57c..bdb11ec5fe 100644 --- a/ebean-test/src/test/java/org/tests/iud/TestCarWheelIud.java +++ b/ebean-test/src/test/java/org/tests/iud/TestCarWheelIud.java @@ -56,7 +56,6 @@ public void test() { Car car2 = DB.find(Car.class, car.getId()); DB.delete(car2); - } @Test