diff --git a/ebean-api/src/main/java/io/ebean/bean/BeanCollection.java b/ebean-api/src/main/java/io/ebean/bean/BeanCollection.java index 3ec5163e3..6271d4051 100644 --- a/ebean-api/src/main/java/io/ebean/bean/BeanCollection.java +++ b/ebean-api/src/main/java/io/ebean/bean/BeanCollection.java @@ -13,12 +13,10 @@ import java.util.Set; * from the Map Set or List. The purpose of gathering the additions and removals * is to support persisting ManyToMany objects. The additions and removals * become inserts and deletes from the intersection table. - *

*

* Technically this is NOT an extension of * java.util.Collection. The reason being that java.util.Map is not a * Collection. I realise this makes this name confusing so I apologise for that. - *

*/ public interface BeanCollection extends Serializable { @@ -68,7 +66,6 @@ public interface BeanCollection extends Serializable { * Return true if the collection is uninitialised or is empty without any held modifications. *

* Returning true means can safely skip cascade save for this bean collection. - *

*/ boolean isSkipSave(); @@ -93,7 +90,6 @@ public interface BeanCollection extends Serializable { *

* That is, if the collection was not loaded due to filterMany predicates etc * then make sure the collection is set to empty. - *

*/ boolean checkEmptyLazyLoad(); @@ -136,10 +132,7 @@ public interface BeanCollection extends Serializable { boolean isReadOnly(); /** - * Add the bean to the collection. - *

- * This is disallowed for BeanMap. - *

+ * Add the bean to the collection. This is disallowed for BeanMap. */ void internalAdd(Object bean); @@ -168,7 +161,6 @@ public interface BeanCollection extends Serializable { * Map.Entry. *

* For maps this returns the entrySet as we need the keys of the map. - *

*/ Collection getActualEntries(); @@ -185,6 +177,11 @@ public interface BeanCollection extends Serializable { */ boolean isReference(); + /** + * Return true if the collection is modify listening and has modifications. + */ + boolean hasModifications(); + /** * Set modify listening on or off. This is used to keep track of objects that * have been added to or removed from the list set or map. @@ -192,7 +189,6 @@ public interface BeanCollection extends Serializable { * This is required only for ManyToMany collections. The additions and * deletions are used to insert or delete entries from the intersection table. * Otherwise modifyListening is false. - *

*/ void setModifyListening(ModifyListenMode modifyListenMode); @@ -206,7 +202,6 @@ public interface BeanCollection extends Serializable { *

* This will potentially end up as an insert into a intersection table for a * ManyToMany. - *

*/ void modifyAddition(E bean); @@ -215,7 +210,6 @@ public interface BeanCollection extends Serializable { *

* This will potentially end up as an delete from an intersection table for a * ManyToMany. - *

*/ void modifyRemoval(Object bean); diff --git a/ebean-api/src/main/java/io/ebean/bean/PersistenceContext.java b/ebean-api/src/main/java/io/ebean/bean/PersistenceContext.java index 8c861af1f..9d67499d1 100644 --- a/ebean-api/src/main/java/io/ebean/bean/PersistenceContext.java +++ b/ebean-api/src/main/java/io/ebean/bean/PersistenceContext.java @@ -1,13 +1,10 @@ package io.ebean.bean; -import java.util.List; - /** * Holds entity beans by there type and id. *

* This is used to ensure only one instance for a given entity type and id is * used to build object graphs from queries and lazy loading. - *

*/ public interface PersistenceContext { @@ -22,7 +19,6 @@ public interface PersistenceContext { *

* Returns an existing entity bean (if one is already there) and otherwise * returns null. - *

*/ Object putIfAbsent(Class rootType, Object id, Object bean); @@ -79,17 +75,11 @@ public interface PersistenceContext { */ boolean resetLimit(); - /** - * Return the list of dirty beans held by this persistence context. - */ - List dirtyBeans(); - /** * Wrapper on a bean to also indicate if a bean has been deleted. *

* If a bean has been deleted then for the same persistence context is should * not be able to be fetched from persistence context or L2 cache. - *

*/ class WithOption { diff --git a/ebean-api/src/main/java/io/ebean/common/AbstractBeanCollection.java b/ebean-api/src/main/java/io/ebean/common/AbstractBeanCollection.java index f1a608361..809ca13b3 100644 --- a/ebean-api/src/main/java/io/ebean/common/AbstractBeanCollection.java +++ b/ebean-api/src/main/java/io/ebean/common/AbstractBeanCollection.java @@ -135,6 +135,11 @@ abstract class AbstractBeanCollection implements BeanCollection { // Support for modify additions deletions etc - ManyToMany // --------------------------------------------------------- + @Override + public boolean hasModifications() { + return modifyHolder != null && modifyHolder.hasModifications(); + } + @Override public ModifyListenMode getModifyListening() { return modifyListenMode; @@ -145,7 +150,6 @@ abstract class AbstractBeanCollection implements BeanCollection { */ @Override public void setModifyListening(ModifyListenMode mode) { - this.modifyListenMode = mode; this.modifyListening = mode != null && ModifyListenMode.NONE != mode; if (modifyListening) { diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/SpiBeanType.java b/ebean-core/src/main/java/io/ebeaninternal/api/SpiBeanType.java new file mode 100644 index 000000000..9923fff3f --- /dev/null +++ b/ebean-core/src/main/java/io/ebeaninternal/api/SpiBeanType.java @@ -0,0 +1,17 @@ +package io.ebeaninternal.api; + +import io.ebean.bean.EntityBean; + +/** + * SPI interface for underlying BeanDescriptor. + */ +public interface SpiBeanType { + + /** + * Return true if the bean contains a many property that has modifications. + *

+ * That is a ManyToMany or a OneToMany with orphan removal with additions + * or removals from the collection. + */ + boolean isToManyDirty(EntityBean bean); +} diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/SpiBeanTypeManager.java b/ebean-core/src/main/java/io/ebeaninternal/api/SpiBeanTypeManager.java new file mode 100644 index 000000000..0a6b79d78 --- /dev/null +++ b/ebean-core/src/main/java/io/ebeaninternal/api/SpiBeanTypeManager.java @@ -0,0 +1,13 @@ +package io.ebeaninternal.api; + +/** + * Manager of SpiBeanTypes. + */ +public interface SpiBeanTypeManager { + + /** + * Return the bean type for the given entity class. + */ + SpiBeanType getBeanType(Class entityType); + +} diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/SpiPersistenceContext.java b/ebean-core/src/main/java/io/ebeaninternal/api/SpiPersistenceContext.java new file mode 100644 index 000000000..a11f9d2f4 --- /dev/null +++ b/ebean-core/src/main/java/io/ebeaninternal/api/SpiPersistenceContext.java @@ -0,0 +1,17 @@ +package io.ebeaninternal.api; + +import io.ebean.bean.PersistenceContext; + +import java.util.List; + +/** + * SPI extension to PersistenceContext. + */ +public interface SpiPersistenceContext extends PersistenceContext { + + /** + * Return the list of dirty beans held by this persistence context. + */ + List dirtyBeans(SpiBeanTypeManager manager); + +} 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 8c59fa7dc..d26ab3ecc 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransaction.java @@ -3,7 +3,6 @@ package io.ebeaninternal.api; import io.ebean.ProfileLocation; import io.ebean.Transaction; import io.ebean.annotation.DocStoreMode; -import io.ebean.bean.PersistenceContext; import io.ebean.event.changelog.BeanChange; import io.ebean.event.changelog.ChangeSet; import io.ebeaninternal.server.core.PersistDeferredRelationship; @@ -196,7 +195,7 @@ public interface SpiTransaction extends Transaction { * later. This is along the lines of 'extended persistence context' * behaviour. */ - PersistenceContext getPersistenceContext(); + SpiPersistenceContext getPersistenceContext(); /** * Set the persistence context to this transaction. @@ -208,7 +207,7 @@ public interface SpiTransaction extends Transaction { * and setPersistenceContext() enable a developer to reuse a single * PersistenceContext with multiple transactions. */ - void setPersistenceContext(PersistenceContext context); + void setPersistenceContext(SpiPersistenceContext context); /** * Return the underlying Connection for internal use. 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 5fd2a3c6e..a63c04cc6 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransactionProxy.java +++ b/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransactionProxy.java @@ -3,7 +3,6 @@ package io.ebeaninternal.api; import io.ebean.ProfileLocation; import io.ebean.TransactionCallback; import io.ebean.annotation.DocStoreMode; -import io.ebean.bean.PersistenceContext; import io.ebean.event.changelog.BeanChange; import io.ebean.event.changelog.ChangeSet; import io.ebeaninternal.server.core.PersistDeferredRelationship; @@ -379,12 +378,12 @@ public abstract class SpiTransactionProxy implements SpiTransaction { } @Override - public PersistenceContext getPersistenceContext() { + public SpiPersistenceContext getPersistenceContext() { return transaction.getPersistenceContext(); } @Override - public void setPersistenceContext(PersistenceContext context) { + public void setPersistenceContext(SpiPersistenceContext context) { transaction.setPersistenceContext(context); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java index 68401b5e3..326cbae00 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java @@ -38,15 +38,7 @@ import io.ebean.plugin.BeanType; import io.ebean.plugin.ExpressionPath; import io.ebean.plugin.Property; import io.ebean.util.SplitName; -import io.ebeaninternal.api.BeanCacheResult; -import io.ebeaninternal.api.CQueryPlanKey; -import io.ebeaninternal.api.ConcurrencyMode; -import io.ebeaninternal.api.LoadBeanContext; -import io.ebeaninternal.api.LoadContext; -import io.ebeaninternal.api.SpiEbeanServer; -import io.ebeaninternal.api.SpiQuery; -import io.ebeaninternal.api.SpiTransaction; -import io.ebeaninternal.api.SpiUpdatePlan; +import io.ebeaninternal.api.*; import io.ebeaninternal.api.TransactionEventTable.TableIUD; import io.ebeaninternal.api.json.SpiJsonReader; import io.ebeaninternal.api.json.SpiJsonWriter; @@ -119,7 +111,7 @@ import static io.ebeaninternal.server.persist.DmlUtil.isNullOrZero; /** * Describes Beans including their deployment information. */ -public class BeanDescriptor implements BeanType, STreeType { +public class BeanDescriptor implements BeanType, STreeType, SpiBeanType { private static final Logger logger = LoggerFactory.getLogger(BeanDescriptor.class); @@ -1880,7 +1872,7 @@ public class BeanDescriptor implements BeanType, STreeType { if (refBean == null) { refBean = createReference(readOnly, false, id, pc); } - return (EntityBean)refBean; + return (EntityBean) refBean; } /** @@ -2937,6 +2929,20 @@ public class BeanDescriptor implements BeanType, STreeType { return false; } + @Override + public boolean isToManyDirty(EntityBean bean) { + final EntityBeanIntercept ebi = bean._ebean_getIntercept(); + for (BeanPropertyAssocMany many : propertiesManySave) { + if (ebi.isLoadedProperty(many.getPropertyIndex())) { + final BeanCollection value = (BeanCollection) many.getValue(bean); + if (value != null && value.hasModifications()) { + return true; + } + } + } + return false; + } + /** * Return true if the bean is draftable and considered a 'live' instance. */ diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java index dca6b2b09..b660c1718 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java @@ -26,9 +26,7 @@ import io.ebean.meta.MetricVisitor; import io.ebean.meta.QueryPlanInit; import io.ebean.plugin.BeanType; import io.ebean.util.AnnotationUtil; -import io.ebeaninternal.api.ConcurrencyMode; -import io.ebeaninternal.api.SpiEbeanServer; -import io.ebeaninternal.api.TransactionEventTable; +import io.ebeaninternal.api.*; import io.ebeaninternal.server.cache.CacheChangeSet; import io.ebeaninternal.server.cache.SpiCacheManager; import io.ebeaninternal.server.core.InternString; @@ -88,7 +86,7 @@ import java.util.concurrent.TimeUnit; /** * Creates BeanDescriptors. */ -public class BeanDescriptorManager implements BeanDescriptorMap { +public class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTypeManager { private static final Logger logger = LoggerFactory.getLogger(BeanDescriptorManager.class); @@ -263,6 +261,11 @@ public class BeanDescriptorManager implements BeanDescriptorMap { return descQueueMap.get(queueId); } + @Override + public SpiBeanType getBeanType(Class entityType) { + return getBeanDescriptor(entityType); + } + @Override @SuppressWarnings("unchecked") public BeanDescriptor getBeanDescriptor(Class entityType) { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/DefaultPersistenceContext.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/DefaultPersistenceContext.java index 27eea2e4c..1064bf8bc 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/DefaultPersistenceContext.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/DefaultPersistenceContext.java @@ -2,6 +2,9 @@ package io.ebeaninternal.server.transaction; import io.ebean.bean.EntityBean; import io.ebean.bean.PersistenceContext; +import io.ebeaninternal.api.SpiBeanType; +import io.ebeaninternal.api.SpiBeanTypeManager; +import io.ebeaninternal.api.SpiPersistenceContext; import java.util.*; import java.util.concurrent.locks.ReentrantLock; @@ -11,19 +14,16 @@ import java.util.concurrent.locks.ReentrantLock; *

* Ensures only one instance of a bean is used according to its type and unique * id. - *

*

* PersistenceContext lives on a Transaction and as such is expected to only * have a single thread accessing it at a time. This is not expected to be used * concurrently. - *

*

* Duplicate beans are ones having the same type and unique id value. These are * considered duplicates and replaced by the bean instance that was already * loaded into the PersistenceContext. - *

*/ -public final class DefaultPersistenceContext implements PersistenceContext { +public final class DefaultPersistenceContext implements SpiPersistenceContext { /** * Map used hold caches. One cache per bean type. @@ -199,12 +199,12 @@ public final class DefaultPersistenceContext implements PersistenceContext { } @Override - public List dirtyBeans() { + public List dirtyBeans(SpiBeanTypeManager manager) { lock.lock(); try { List list = new ArrayList<>(); for (ClassContext classContext : typeCache.values()) { - classContext.dirtyBeans(list); + classContext.dirtyBeans(manager, list); } return list; } finally { @@ -223,26 +223,26 @@ public final class DefaultPersistenceContext implements PersistenceContext { } private ClassContext getClassContext(Class rootType) { - return typeCache.computeIfAbsent(rootType, k -> new ClassContext()); + return typeCache.computeIfAbsent(rootType, k -> new ClassContext(rootType)); } private static class ClassContext { private final Map map = new HashMap<>(); - + private final Class rootType; private Set deleteSet; - private int initialSize; - private ClassContext parent; - private ClassContext() { + private ClassContext(Class rootType) { + this.rootType = rootType; } /** * Create as a shallow copy. */ private ClassContext(ClassContext source, boolean initial) { + this.rootType = source.rootType; if (initial || source.isTransfer()) { parent = source.transferParent(); initialSize = parent.size(); @@ -334,9 +334,11 @@ public final class DefaultPersistenceContext implements PersistenceContext { /** * Add the dirty beans to the list. */ - void dirtyBeans(List list) { + void dirtyBeans(SpiBeanTypeManager manager, List list) { + final SpiBeanType beanType = manager.getBeanType(rootType); for (Object value : map.values()) { - if (((EntityBean) value)._ebean_getIntercept().isDirty()) { + EntityBean bean = (EntityBean) value; + if (bean._ebean_getIntercept().isDirty() || beanType.isToManyDirty(bean)) { list.add(value); } } 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 5f2b5d195..e4e36e337 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 @@ -3,13 +3,9 @@ package io.ebeaninternal.server.transaction; import io.ebean.ProfileLocation; import io.ebean.TransactionCallback; import io.ebean.annotation.DocStoreMode; -import io.ebean.bean.PersistenceContext; import io.ebean.event.changelog.BeanChange; import io.ebean.event.changelog.ChangeSet; -import io.ebeaninternal.api.SpiProfileTransactionEvent; -import io.ebeaninternal.api.SpiTransaction; -import io.ebeaninternal.api.TransactionEvent; -import io.ebeaninternal.api.TxnProfileEventCodes; +import io.ebeaninternal.api.*; import io.ebeaninternal.server.core.PersistDeferredRelationship; import io.ebeaninternal.server.core.PersistRequestBean; import io.ebeaninternal.server.persist.BatchControl; @@ -58,7 +54,7 @@ class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEventCode /** * Holder of the objects fetched to ensure unique objects are used. */ - private PersistenceContext persistenceContext; + private SpiPersistenceContext persistenceContext; private Object tenantId; @@ -421,7 +417,7 @@ class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEventCode * Return the persistence context associated with this transaction. */ @Override - public PersistenceContext getPersistenceContext() { + public SpiPersistenceContext getPersistenceContext() { return persistenceContext; } @@ -434,7 +430,7 @@ class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEventCode *

*/ @Override - public void setPersistenceContext(PersistenceContext context) { + public void setPersistenceContext(SpiPersistenceContext context) { if (!isActive()) { throw new IllegalStateException(illegalStateMessage); } 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 9f59c44bd..b4bd7b714 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 @@ -3,20 +3,16 @@ package io.ebeaninternal.server.transaction; import io.ebean.ProfileLocation; import io.ebean.TransactionCallback; import io.ebean.annotation.DocStoreMode; -import io.ebean.bean.PersistenceContext; import io.ebean.config.DatabaseConfig; import io.ebean.config.dbplatform.DatabasePlatform.OnQueryOnly; import io.ebean.event.changelog.BeanChange; import io.ebean.event.changelog.ChangeSet; -import io.ebeaninternal.api.SpiProfileTransactionEvent; -import io.ebeaninternal.api.SpiTransaction; -import io.ebeaninternal.api.TransactionEvent; -import io.ebeaninternal.api.TxnProfileEventCodes; +import io.ebeaninternal.api.*; import io.ebeaninternal.server.core.PersistDeferredRelationship; import io.ebeaninternal.server.core.PersistRequestBean; -import io.ebeaninternal.server.util.Str; import io.ebeaninternal.server.persist.BatchControl; import io.ebeaninternal.server.persist.BatchedSqlException; +import io.ebeaninternal.server.util.Str; import io.ebeanservice.docstore.api.DocStoreTransaction; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -25,12 +21,7 @@ import javax.persistence.PersistenceException; import javax.persistence.RollbackException; import java.sql.Connection; import java.sql.SQLException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.IdentityHashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.function.Consumer; /** @@ -99,7 +90,7 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { /** * Holder of the objects fetched to ensure unique objects are used. */ - private PersistenceContext persistenceContext; + private SpiPersistenceContext persistenceContext; /** * Used to give developers more control over the insert update and delete @@ -806,7 +797,7 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { * Return the persistence context associated with this transaction. */ @Override - public PersistenceContext getPersistenceContext() { + public SpiPersistenceContext getPersistenceContext() { return persistenceContext; } @@ -816,10 +807,9 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { * This could be considered similar to EJB3 Extended PersistanceContext. In * that you get the PersistanceContext from a transaction, hold onto it, and * then set it back later to a second transaction. - *

*/ @Override - public void setPersistenceContext(PersistenceContext context) { + public void setPersistenceContext(SpiPersistenceContext context) { if (!isActive()) { throw new IllegalStateException(illegalStateMessage); } 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 0d3c82cd6..d435e93fd 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 @@ -3,9 +3,9 @@ package io.ebeaninternal.server.transaction; import io.ebean.ProfileLocation; import io.ebean.TransactionCallback; import io.ebean.annotation.DocStoreMode; -import io.ebean.bean.PersistenceContext; import io.ebean.event.changelog.BeanChange; import io.ebean.event.changelog.ChangeSet; +import io.ebeaninternal.api.SpiPersistenceContext; import io.ebeaninternal.api.SpiProfileTransactionEvent; import io.ebeaninternal.api.SpiTransaction; import io.ebeaninternal.api.TransactionEvent; @@ -349,12 +349,12 @@ class NoTransaction implements SpiTransaction { } @Override - public PersistenceContext getPersistenceContext() { + public SpiPersistenceContext getPersistenceContext() { return null; } @Override - public void setPersistenceContext(PersistenceContext context) { + public void setPersistenceContext(SpiPersistenceContext context) { } @Override diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java index 0728eebac..e3fbdd425 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java @@ -5,7 +5,6 @@ import io.ebean.ProfileLocation; import io.ebean.TxScope; import io.ebean.annotation.PersistBatch; import io.ebean.annotation.TxType; -import io.ebean.bean.PersistenceContext; import io.ebean.cache.ServerCacheNotification; import io.ebean.cache.ServerCacheNotify; import io.ebean.config.CurrentTenantProvider; @@ -19,15 +18,7 @@ import io.ebean.metric.MetricFactory; import io.ebean.metric.TimedMetric; import io.ebean.metric.TimedMetricMap; import io.ebean.plugin.SpiServer; -import io.ebeaninternal.api.ScopeTrans; -import io.ebeaninternal.api.ScopedTransaction; -import io.ebeaninternal.api.SpiLogManager; -import io.ebeaninternal.api.SpiLogger; -import io.ebeaninternal.api.SpiProfileHandler; -import io.ebeaninternal.api.SpiTransaction; -import io.ebeaninternal.api.SpiTransactionManager; -import io.ebeaninternal.api.TransactionEvent; -import io.ebeaninternal.api.TransactionEventTable; +import io.ebeaninternal.api.*; import io.ebeaninternal.api.TransactionEventTable.TableIUD; import io.ebeaninternal.server.cache.CacheChangeSet; import io.ebeaninternal.server.cluster.ClusterManager; @@ -770,8 +761,8 @@ public class TransactionManager implements SpiTransactionManager { /** * Experimental - find dirty beans in the persistence context and persist them. */ - public void flushTransparent(PersistenceContext persistenceContext, SpiTransaction transaction) { - List dirtyBeans = persistenceContext.dirtyBeans(); + public void flushTransparent(SpiPersistenceContext persistenceContext, SpiTransaction transaction) { + List dirtyBeans = persistenceContext.dirtyBeans(beanDescriptorManager); if (!dirtyBeans.isEmpty()) { server.updateAll(dirtyBeans, transaction); } diff --git a/ebean-core/src/test/java/org/tests/model/basic/Order.java b/ebean-core/src/test/java/org/tests/model/basic/Order.java index b15765b51..cea0a6e00 100644 --- a/ebean-core/src/test/java/org/tests/model/basic/Order.java +++ b/ebean-core/src/test/java/org/tests/model/basic/Order.java @@ -101,7 +101,7 @@ public class Order implements Serializable { @DocEmbedded List details; - @OneToMany(cascade = CascadeType.ALL, mappedBy = "order") + @OneToMany(cascade = CascadeType.ALL, mappedBy = "order", orphanRemoval = true) List shipments; @Override diff --git a/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java b/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java index 0ed40203f..8a870f8ab 100644 --- a/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java +++ b/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java @@ -2,9 +2,11 @@ package org.tests.transparentpersist; import io.ebean.*; import io.ebean.annotation.*; +import io.ebeaninternal.api.SpiBeanTypeManager; import io.ebeaninternal.api.SpiTransaction; import io.ebeantest.LoggedSql; import org.junit.Test; +import org.mockito.Mockito; import org.tests.model.basic.Customer; import org.tests.model.basic.EBasicVer; import org.tests.model.basic.Order; @@ -200,8 +202,6 @@ public class TestTransparentPersist extends BaseTestCase { foundOrder.getShipments().remove(0); OrderShipment osh2 = new OrderShipment(); foundOrder.addShipment(osh2); - // if this is called insert is performed but no delete - // DB.save(foundOrder); transaction.commit(); } @@ -305,7 +305,8 @@ public class TestTransparentPersist extends BaseTestCase { } private List getDirtyBeansFromPersistenceContext(Transaction transaction) { - return ((SpiTransaction)transaction).getPersistenceContext().dirtyBeans(); + final SpiBeanTypeManager mgr = Mockito.mock(SpiBeanTypeManager.class); + return ((SpiTransaction)transaction).getPersistenceContext().dirtyBeans(mgr); } }