#461 - ENH: Add @Draftable support - publish

This commit is contained in:
Robin Bygrave
2015-11-23 21:28:58 +13:00
parent fd9a5167b1
commit db371cbc6a
24 changed files with 311 additions and 80 deletions
@@ -1825,12 +1825,12 @@ public interface EbeanServer {
* The values are published from the draft to the live bean.
* </p>
*
* @param <T> the type of the entity bean
* @param beanType the type of the entity bean
* @param id the id of the entity bean
* @param transaction the transaction the publish process should use
* @param <T> the type of the entity bean
*/
<T> void publish(Class<T> beanType, Object id, Transaction transaction);
<T> T publish(Class<T> beanType, Object id, Transaction transaction);
/**
* Publish the beans that match the query.
@@ -1838,10 +1838,10 @@ public interface EbeanServer {
* The values are published from the draft beans to the live beans.
* </p>
*
* @param <T> the type of the entity bean
* @param query the query used to select the draft beans to publish
* @param transaction the transaction the publish process should use
* @param <T> the type of the entity bean
*/
<T> void publish(Query<T> query, Transaction transaction);
<T> List<T> publish(Query<T> query, Transaction transaction);
}
@@ -31,6 +31,16 @@ public interface BeanCollection<E> extends Serializable {
ALL
}
/**
* Add a bean to the list/set with modifyListen notification.
*/
void addBean(E bean);
/**
* Remove a bean to the list/set with modifyListen notification.
*/
void removeBean(E bean);
/**
* Reset the collection back to an empty state ready for reloading.
* <p>
@@ -12,5 +12,5 @@ public interface BeanCollectionAdd {
/**
* Add a loaded bean to the collection.
*/
void addBean(EntityBean bean);
void addEntityBean(EntityBean bean);
}
@@ -60,7 +60,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
}
@SuppressWarnings("unchecked")
public void addBean(EntityBean bean) {
public void addEntityBean(EntityBean bean) {
list.add((E) bean);
}
@@ -206,6 +206,11 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
list.add(index, element);
}
@Override
public void addBean(E bean) {
add(bean);
}
public boolean add(E o) {
checkReadOnly();
init();
@@ -319,6 +324,13 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
return list.listIterator(index);
}
@Override
public void removeBean(E bean) {
if (list.remove(bean)) {
getModifyHolder().modifyRemoval(bean);
}
}
public E remove(int index) {
checkReadOnly();
init();
@@ -272,6 +272,16 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
map.putAll(puts);
}
@Override
public void addBean(E bean) {
throw new IllegalStateException("Method not allowed on Map. Please use List instead.");
}
@Override
public void removeBean(E bean) {
throw new IllegalStateException("Method not allowed on Map. Please use List instead.");
}
public E remove(Object key) {
checkReadOnly();
init();
@@ -53,7 +53,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
}
@SuppressWarnings("unchecked")
public void addBean(EntityBean bean) {
public void addEntityBean(EntityBean bean) {
set.add((E) bean);
}
@@ -174,6 +174,18 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
return set.hashCode();
}
@Override
public void addBean(E bean) {
add(bean);
}
@Override
public void removeBean(E bean) {
if (set.remove(bean)) {
getModifyHolder().modifyRemoval(bean);
}
}
// -----------------------------------------------------//
// proxy method for map
// -----------------------------------------------------//
@@ -3,11 +3,14 @@ package com.avaje.ebean.dbmigration.model.build;
import com.avaje.ebean.config.DbConstraintNaming;
import com.avaje.ebean.config.dbplatform.DbType;
import com.avaje.ebean.config.dbplatform.DbTypeMap;
import com.avaje.ebean.dbmigration.model.MColumn;
import com.avaje.ebean.dbmigration.model.MTable;
import com.avaje.ebean.dbmigration.model.ModelContainer;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.type.ScalarType;
import java.util.Collection;
/**
* The context used during DDL generation.
*/
@@ -128,4 +131,30 @@ public class ModelBuildContext {
return dbTypeMap.get(dbType);
}
/**
* Create the draft table for a given table.
*/
public void createDraft(MTable table) {
MTable draftTable = table.createDraftTable();
draftTable.setPkName(primaryKeyName(draftTable.getName()));
int fkCount = 0;
int ixCount = 0;
Collection<MColumn> cols = draftTable.getColumns().values();
for (MColumn col: cols) {
if (col.getForeignKeyName() != null) {
// Note that we adjust the 'references' table later in a second pass
// after we know all the tables that are 'draftable'
//col.setReferences(refTable + "." + refColumn);
col.setForeignKeyName(foreignKeyConstraintName(draftTable.getName(), col.getName(), ++fkCount));
String[] indexCols = {col.getName()};
col.setForeignKeyIndex(foreignKeyIndexName(draftTable.getName(), indexCols, ++ixCount));
}
}
addTable(draftTable);
}
}
@@ -42,6 +42,11 @@ public class ModelBuildIntersectionTable {
}
buildFkConstraints();
if (manyProp.getTargetDescriptor().isDraftable()) {
ctx.createDraft(intersectionTable);
}
}
private void buildFkConstraints() {
@@ -112,24 +112,7 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
private void addDraftTable() {
if (beanDescriptor.isDraftable() || beanDescriptor.isDraftableElement()) {
// create a 'Draft' table which looks very similar (change PK, FK etc)
MTable draftTable = table.createDraftTable();
draftTable.setPkName(ctx.primaryKeyName(draftTable.getName()));
int fkCount = 0;
int ixCount = 0;
Collection<MColumn> cols = draftTable.getColumns().values();
for (MColumn col: cols) {
if (col.getForeignKeyName() != null) {
// Note that we adjust the 'references' table later in a second pass
// after we know all the tables that are 'draftable'
//col.setReferences(refTable + "." + refColumn);
col.setForeignKeyName(ctx.foreignKeyConstraintName(draftTable.getName(), col.getName(), ++fkCount));
String[] indexCols = {col.getName()};
col.setForeignKeyIndex(ctx.foreignKeyIndexName(draftTable.getName(), indexCols, ++ixCount));
}
}
ctx.addTable(draftTable);
ctx.createDraft(table);
}
}
@@ -1625,14 +1625,16 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
}
}
public <T> void publish(Query<T> query, Transaction transaction) {
public <T> List<T> publish(Query<T> query, Transaction transaction) {
TransWrapper wrap = initTransIfRequired(transaction);
try {
SpiTransaction trans = wrap.transaction;
persister.publish(query, trans);
List<T> liveBeans = persister.publish(query, trans);
wrap.commitIfCreated();
return liveBeans;
} catch (RuntimeException e) {
wrap.rollbackIfCreated();
throw e;
@@ -1640,10 +1642,11 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
}
@Override
public <T> void publish(Class<T> beanType, Object id, Transaction transaction) {
public <T> T publish(Class<T> beanType, Object id, Transaction transaction) {
Query<T> query = find(beanType).setId(id);
publish(query, transaction);
List<T> liveBeans = publish(query, transaction);
return (liveBeans.size() == 1) ? liveBeans.get(0) : null;
}
private EntityBean checkEntityBean(Object bean) {
@@ -231,7 +231,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
}
public boolean isNotify() {
this.notifyCache = beanDescriptor.isCacheNotify();
this.notifyCache = beanDescriptor.isCacheNotify(publish);
return notifyCache || isNotifyPersistListener();
}
@@ -1,6 +1,7 @@
package com.avaje.ebeaninternal.server.core;
import java.util.Collection;
import java.util.List;
import com.avaje.ebean.CallableSql;
import com.avaje.ebean.Query;
@@ -90,6 +91,6 @@ public interface Persister {
/**
* Publish the draft beans matching the given query.
*/
<T> void publish(Query<T> query, Transaction transaction);
<T> List<T> publish(Query<T> query, Transaction transaction);
}
@@ -51,8 +51,8 @@ public class BeanCascadeInfo {
/**
* Set to true if delete should cascade.
*/
public void setDelete(boolean isDelete) {
this.delete = isDelete;
public void setDelete(boolean delete) {
this.delete = delete;
}
/**
* Return true if save should cascade.
@@ -60,5 +60,13 @@ public class BeanCascadeInfo {
public boolean isSave() {
return save;
}
/**
* Set cascade save and delete settings.
*/
public void setSaveDelete(boolean save, boolean delete) {
this.save = save;
this.delete = delete;
}
}
@@ -572,16 +572,21 @@ public class BeanDescriptor<T> implements MetaBeanInfo, SpiBeanType<T> {
*
* @param asOfTableMap the map of base tables to associated 'with history' tables
* @param asOfViewSuffix the suffix added to the table name to derive the 'with history' view name
* @param draftTableMap the map of base tables to associated 'draft' tables.
*/
public void initialiseOther(Map<String, String> asOfTableMap, String asOfViewSuffix) {
public void initialiseOther(Map<String, String> asOfTableMap, String asOfViewSuffix, Map<String, String> draftTableMap) {
for (int i = 0; i < propertiesManyToMany.length; i++) {
// register associated draft table for M2M intersection
propertiesManyToMany[i].registerDraftIntersectionTable(draftTableMap);
}
if (historySupport) {
// history support on this bean so check all associated intersection tables
// and if they are not excluded register the associated 'with history' table
for (int i = 0; i < propertiesManyToMany.length; i++) {
// register associated history table for M2M intersection
if (!propertiesManyToMany[i].isExcludedFromHistory()) {
// this intersection table has history support so also register
// it into the asOfTableMap
TableJoin intersectionTableJoin = propertiesManyToMany[i].getIntersectionTableJoin();
String intersectionTableName = intersectionTableJoin.getTable();
asOfTableMap.put(intersectionTableName, intersectionTableName + asOfViewSuffix);
@@ -849,7 +854,11 @@ public class BeanDescriptor<T> implements MetaBeanInfo, SpiBeanType<T> {
/**
* Return true if the persist request needs to notify the cache.
*/
public boolean isCacheNotify() {
public boolean isCacheNotify(boolean publish) {
if (draftable && !publish) {
// no caching when editing draft beans
return false;
}
return cacheHelp.isCacheNotify();
}
@@ -31,13 +31,22 @@ public final class BeanDescriptorDraftHelp<T> {
EntityBean live = (EntityBean)liveBean;
BeanProperty idProperty = desc.getIdProperty();
idProperty.publish(draft, live);
if (idProperty != null) {
idProperty.publish(draft, live);
}
BeanProperty[] props = desc.propertiesNonMany();
for (int i = 0; i < props.length; i++) {
props[i].publish(draft, live);
}
BeanPropertyAssocMany<?>[] many = desc.propertiesMany();
for (int i = 0; i < many.length; i++) {
if (many[i].getTargetDescriptor().isDraftable()) {
many[i].publishMany(draft, live);
}
}
return liveBean;
}
}
@@ -5,6 +5,7 @@ import com.avaje.ebean.Model;
import com.avaje.ebean.RawSql;
import com.avaje.ebean.RawSqlBuilder;
import com.avaje.ebean.annotation.ConcurrencyMode;
import com.avaje.ebean.bean.BeanCollection;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.cache.ServerCacheManager;
import com.avaje.ebean.config.EncryptKey;
@@ -423,7 +424,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
// also look for intersection tables with
// associated history support and register them
// into the asOfTableMap
d.initialiseOther(asOfTableMap, asOfViewSuffix);
d.initialiseOther(asOfTableMap, asOfViewSuffix, draftTableMap);
}
// create BeanManager for each non-embedded entity bean
@@ -910,7 +911,13 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
*/
private void checkMappedByOneToMany(DeployBeanInfo<?> info, DeployBeanPropertyAssocMany<?> prop) {
// get the bean descriptor that holds the mappedBy property
DeployBeanDescriptor<?> targetDesc = getTargetDescriptor(prop);
if (targetDesc.isDraftableElement()) {
// automatically turning on orphan removal and CascadeType.ALL
prop.setModifyListenMode(BeanCollection.ModifyListenMode.REMOVALS);
prop.getCascadeInfo().setSaveDelete(true, true);
}
if (prop.getMappedBy() == null) {
if (!findMappedBy(prop)) {
@@ -924,7 +931,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
String mappedBy = prop.getMappedBy();
// get the mappedBy property
DeployBeanDescriptor<?> targetDesc = getTargetDescriptor(prop);
DeployBeanProperty mappedProp = targetDesc.getBeanProperty(mappedBy);
if (mappedProp == null) {
@@ -960,6 +966,9 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
// get the bean descriptor that holds the mappedBy property
String mappedBy = prop.getMappedBy();
if (mappedBy == null) {
if (getTargetDescriptor(prop).isDraftable()) {
prop.setIntersectionDraftTable();
}
return;
}
@@ -1007,6 +1016,10 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
DeployTableJoin inverseJoin = new DeployTableJoin();
mappedIntJoin.copyTo(inverseJoin, false, intTableName);
prop.setInverseJoin(inverseJoin);
if (targetDesc.isDraftable()) {
prop.setIntersectionDraftTable();
}
}
private <T> void setBeanControllerFinderListener(DeployBeanDescriptor<T> descriptor) {
@@ -84,7 +84,7 @@ public final class BeanMapHelp<T> implements BeanCollectionHelp<T> {
this.map = map;
}
public void addBean(EntityBean bean) {
public void addEntityBean(EntityBean bean) {
Object keyValue = beanProperty.getValue(bean);
map.put(keyValue, bean);
}
@@ -23,6 +23,7 @@ import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -39,6 +40,8 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> {
* Join for manyToMany intersection table.
*/
private final TableJoin intersectionJoin;
private final String intersectionPublishTable;
private final String intersectionDraftTable;
/**
* For ManyToMany this is the Inverse join used to build reference queries.
@@ -109,6 +112,13 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> {
this.mapKey = deploy.getMapKey();
this.fetchOrderBy = deploy.getFetchOrderBy();
this.intersectionJoin = deploy.createIntersectionTableJoin();
if (intersectionJoin != null) {
this.intersectionPublishTable = intersectionJoin.getTable();
this.intersectionDraftTable = deploy.getIntersectionDraftTable();
} else {
this.intersectionPublishTable = null;
this.intersectionDraftTable = null;
}
this.inverseJoin = deploy.createInverseTableJoin();
this.modifyListenMode = deploy.getModifyListenMode();
this.jsonHelp = new BeanPropertyAssocManyJsonHelp(this);
@@ -798,22 +808,39 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> {
return row;
}
public IntersectionRow buildManyToManyDeleteChildren(EntityBean parentBean) {
public IntersectionRow buildManyToManyDeleteChildren(EntityBean parentBean, boolean publish) {
IntersectionRow row = new IntersectionRow(intersectionJoin.getTable());
String tableName = publish ? intersectionPublishTable : intersectionDraftTable;
IntersectionRow row = new IntersectionRow(tableName);
buildExport(row, parentBean);
return row;
}
public IntersectionRow buildManyToManyMapBean(EntityBean parent, EntityBean other) {
IntersectionRow row = new IntersectionRow(intersectionJoin.getTable());
public IntersectionRow buildManyToManyMapBean(EntityBean parent, EntityBean other, boolean publish) {
String tableName = publish ? intersectionPublishTable : intersectionDraftTable;
IntersectionRow row = new IntersectionRow(tableName);
buildExport(row, parent);
buildImport(row, other);
return row;
}
/**
* Register the mapping of intersection table to associated draft table.
*/
public void registerDraftIntersectionTable(Map<String, String> draftTableMap) {
if (hasDraftIntersection()) {
draftTableMap.put(intersectionPublishTable, intersectionDraftTable);
}
}
/**
* Return true if the relationship is a ManyToMany with the intersection having an associated draft table.
*/
private boolean hasDraftIntersection() {
return intersectionDraftTable != null && !intersectionDraftTable.equals(intersectionPublishTable);
}
private void buildExport(IntersectionRow row, EntityBean parentBean) {
if (embeddedExportedProperties) {
@@ -876,4 +903,57 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> {
public void jsonRead(ReadJson readJson, EntityBean parentBean) throws IOException {
jsonHelp.jsonRead(readJson, parentBean);
}
public void publishMany(EntityBean draft, EntityBean live) {
// collections will not be null due to enhancement
BeanCollection<T> draftVal = (BeanCollection<T>)getValueIntercept(draft);
BeanCollection<T> liveVal = (BeanCollection<T>)getValueIntercept(live);
// Organise the existing live beans into map keyed by id
Map<Object, T> liveBeansAsMap = liveBeansAsMap(liveVal);
// publish from each draft to live bean creating new live beans as required
draftVal.size();
Collection<T> actualDetails = draftVal.getActualDetails();
for (T bean : actualDetails) {
Object id = targetDescriptor.getId((EntityBean) bean);
T liveBean = liveBeansAsMap.remove(id);
if (isManyToMany()) {
if (liveBean == null) {
// add new relationship (Map not allowed here)
liveVal.addBean(targetDescriptor.createReference(Boolean.FALSE, id));
}
} else {
// recursively publish the OneToMany child bean
T newLive = targetDescriptor.publish(bean, liveBean);
if (liveBean == null) {
// Map not allowed here
liveVal.addBean(newLive);
}
}
}
// anything remaining should be deleted (so remove from modify aware collection)
Collection<T> values = liveBeansAsMap.values();
for (T value : values) {
liveVal.removeBean(value);
}
}
private Map<Object,T> liveBeansAsMap(BeanCollection<?> liveVal) {
liveVal.size();
Collection<?> liveBeans = liveVal.getActualDetails();
Map<Object,T> liveMap = new LinkedHashMap<Object, T>();
for (Object liveBean : liveBeans) {
Object id = targetDescriptor.getId((EntityBean) liveBean);
liveMap.put(id, (T)liveBean);
}
return liveMap;
}
}
@@ -65,7 +65,7 @@ public class BeanPropertyAssocManyJsonHelp {
// read the entire array
break;
}
add.addBean(detailBean);
add.addEntityBean(detailBean);
if (parentBean != null && many.childMasterProperty != null) {
// bind detail bean back to master via mappedBy property
@@ -216,6 +216,7 @@ public class DeployBeanDescriptor<T> {
}
public void setDraftableElement() {
draftable = true;
draftableElement = true;
}
@@ -9,6 +9,11 @@ import com.avaje.ebeaninternal.server.deploy.TableJoin;
*/
public class DeployBeanPropertyAssocMany<T> extends DeployBeanPropertyAssoc<T> {
/**
* The type of the many, set, list or map.
*/
final ManyType manyType;
ModifyListenMode modifyListenMode = ModifyListenMode.NONE;
/**
@@ -35,12 +40,9 @@ public class DeployBeanPropertyAssocMany<T> extends DeployBeanPropertyAssoc<T> {
String mapKey;
/**
* The type of the many, set, list or map.
*/
final ManyType manyType;
String intersectionDraftTable;
/**
/**
* Create this property.
*/
public DeployBeanPropertyAssocMany(DeployBeanDescriptor<?> desc, Class<T> targetType, ManyType manyType) {
@@ -191,4 +193,17 @@ public class DeployBeanPropertyAssocMany<T> extends DeployBeanPropertyAssoc<T> {
}
}
/**
* Return a draft table for intersection between 2 @Draftable entities.
*/
public String getIntersectionDraftTable() {
return (intersectionDraftTable != null) ? intersectionDraftTable : intersectionJoin.getTable();
}
/**
* ManyToMany between 2 @Draftable entities to also need draft intersection table.
*/
public void setIntersectionDraftTable() {
this.intersectionDraftTable = intersectionJoin.getTable()+"_draft";
}
}
@@ -58,6 +58,8 @@ import java.util.Set;
*/
public final class DefaultPersister implements Persister {
private static final Logger PUB = LoggerFactory.getLogger("org.avaje.ebean.PUB");
private static final Logger logger = LoggerFactory.getLogger(DefaultPersister.class);
/**
@@ -125,15 +127,20 @@ public final class DefaultPersister implements Persister {
}
@Override
public <T> void publish(Query<T> query, Transaction transaction) {
public <T> List<T> publish(Query<T> query, Transaction transaction) {
query.asDraft();
Class<T> beanType = query.getBeanType();
List<T> draftBeans = server.findList(query, transaction);
BeanDescriptor<T> desc = server.getBeanDescriptor(beanType);
if (draftBeans.isEmpty()) {
throw new IllegalArgumentException("No draft beans found to publish");
}
PUB.debug("publish [{}] count:{}", desc.getName(), draftBeans.size());
// get the list of Id's
List<Object> idList = new ArrayList<Object>();
for (T draftBean: draftBeans) {
@@ -157,16 +164,21 @@ public final class DefaultPersister implements Persister {
livePublish.add(liveBean);
Type persistType = (existingLiveBean == null) ? Type.INSERT : Type.UPDATE;
PersistRequestBean<T> request = createRequest(liveBean, transaction, null, mgr, persistType, false);
PersistRequestBean<T> request = createRequest(liveBean, transaction, null, mgr, persistType, true);
request.setPublish();
PUB.trace("publish [{}] id[{}]", desc.getName(), draftID);
if (persistType == Type.INSERT) {
insert(request);
} else {
update(request);
}
PUB.debug("publish complete for type:{}", desc.getName());
}
return livePublish;
}
/**
@@ -242,10 +254,13 @@ public final class DefaultPersister implements Persister {
}
}
private void saveRecurse(EntityBean bean, Transaction t, Object parentBean, boolean insertMode) {
private void saveRecurse(EntityBean bean, Transaction t, Object parentBean, boolean insertMode, boolean publish) {
// determine insert or update taking into account stateless updates
PersistRequestBean<?> request = createRequest(bean, t, parentBean, insertMode);
PersistRequestBean<?> request = createRequestRecurse(bean, t, parentBean, insertMode, publish);
if (publish) {
request.setPublish();
}
if (request.isReference()) {
// its a reference...
@@ -586,7 +601,7 @@ public final class DefaultPersister implements Persister {
if (!prop.isSaveRecurseSkippable(detailBean)) {
t.depth(+1);
prop.setParentBeanToChild(parentBean, detailBean);
saveRecurse(detailBean, t, parentBean, insertMode);
saveRecurse(detailBean, t, parentBean, insertMode, request.isPublish());
t.depth(-1);
}
}
@@ -617,6 +632,7 @@ public final class DefaultPersister implements Persister {
private final SpiTransaction transaction;
private final boolean cascade;
private final boolean deleteMissingChildren;
private final boolean publish;
private SaveManyPropRequest(boolean insertedParent, BeanPropertyAssocMany<?> many, EntityBean parentBean, PersistRequestBean<?> request) {
this.insertedParent = insertedParent;
@@ -625,6 +641,7 @@ public final class DefaultPersister implements Persister {
this.parentBean = parentBean;
this.transaction = request.getTransaction();
this.deleteMissingChildren = request.isDeleteMissingChildren();
this.publish = request.isPublish();
}
private SaveManyPropRequest(BeanPropertyAssocMany<?> many, EntityBean parentBean, SpiTransaction t) {
@@ -634,6 +651,7 @@ public final class DefaultPersister implements Persister {
this.transaction = t;
this.cascade = true;
this.deleteMissingChildren = false;
this.publish = false;
}
public boolean isSaveIntersection() {
@@ -680,6 +698,10 @@ public final class DefaultPersister implements Persister {
}
c.modifyReset();
}
public boolean isPublish() {
return publish;
}
}
private void saveMany(SaveManyPropRequest saveMany, boolean insertMode) {
@@ -817,7 +839,7 @@ public final class DefaultPersister implements Persister {
}
if (!skipSavingThisBean) {
saveRecurse(detail, t, parentBean, insertMode);
saveRecurse(detail, t, parentBean, insertMode, saveMany.isPublish());
}
}
}
@@ -850,7 +872,7 @@ public final class DefaultPersister implements Persister {
BeanDescriptor<?> descriptor = beanDescriptorManager.getBeanDescriptor(ownerBean.getClass());
BeanPropertyAssocMany<?> prop = (BeanPropertyAssocMany<?>) descriptor.getBeanProperty(propertyName);
return deleteAssocManyIntersection(ownerBean, prop, t);
return deleteAssocManyIntersection(ownerBean, prop, t, false);
}
public void saveManyToManyAssociations(EntityBean ownerBean, String propertyName, Transaction t) {
@@ -884,7 +906,7 @@ public final class DefaultPersister implements Persister {
int revertDepth = -1 * depth;
trans.depth(depth);
saveRecurse(assocBean, t, parentBean, true);
saveRecurse(assocBean, t, parentBean, true, false);
trans.depth(revertDepth);
} else {
@@ -915,7 +937,7 @@ public final class DefaultPersister implements Persister {
if (vanillaCollection || deleteMissingChildren) {
// delete all intersection rows and then treat all
// beans in the collection as additions
deleteAssocManyIntersection(saveManyPropRequest.getParentBean(), prop, t);
deleteAssocManyIntersection(saveManyPropRequest.getParentBean(), prop, t, saveManyPropRequest.isPublish());
}
Collection<?> deletions = null;
@@ -967,7 +989,7 @@ public final class DefaultPersister implements Persister {
} else {
// build a intersection row for 'insert'
IntersectionRow intRow = prop.buildManyToManyMapBean(saveManyPropRequest.getParentBean(), otherBean);
IntersectionRow intRow = prop.buildManyToManyMapBean(saveManyPropRequest.getParentBean(), otherBean, saveManyPropRequest.isPublish());
SqlUpdate sqlInsert = intRow.createInsert(server);
executeSqlUpdate(sqlInsert, t);
}
@@ -983,7 +1005,7 @@ public final class DefaultPersister implements Persister {
EntityBean otherDelete = (EntityBean) other;
// the object from the 'other' side of the ManyToMany
// build a intersection row for 'delete'
IntersectionRow intRow = prop.buildManyToManyMapBean(saveManyPropRequest.getParentBean(), otherDelete);
IntersectionRow intRow = prop.buildManyToManyMapBean(saveManyPropRequest.getParentBean(), otherDelete, saveManyPropRequest.isPublish());
SqlUpdate sqlDelete = intRow.createDelete(server);
executeSqlUpdate(sqlDelete, t);
}
@@ -993,10 +1015,10 @@ public final class DefaultPersister implements Persister {
t.depth(-1);
}
private int deleteAssocManyIntersection(EntityBean bean, BeanPropertyAssocMany<?> many, Transaction t) {
private int deleteAssocManyIntersection(EntityBean bean, BeanPropertyAssocMany<?> many, Transaction t, boolean publish) {
// delete all intersection rows for this bean
IntersectionRow intRow = many.buildManyToManyDeleteChildren(bean);
IntersectionRow intRow = many.buildManyToManyDeleteChildren(bean, publish);
SqlUpdate sqlDelete = intRow.createDeleteChildren(server);
return executeSqlUpdate(sqlDelete, t);
@@ -1045,7 +1067,7 @@ public final class DefaultPersister implements Persister {
for (int i = 0; i < manys.length; i++) {
if (manys[i].isManyToMany()) {
// delete associated rows from intersection table
deleteAssocManyIntersection(parentBean, manys[i], t);
deleteAssocManyIntersection(parentBean, manys[i], t, request.isPublish());
} else {
@@ -1149,7 +1171,7 @@ public final class DefaultPersister implements Persister {
&& !request.isParent(detailBean)) {
SpiTransaction t = request.getTransaction();
t.depth(-1);
saveRecurse(detailBean, t, null, insertMode);
saveRecurse(detailBean, t, null, insertMode, request.isPublish());
t.depth(+1);
}
}
@@ -1247,15 +1269,21 @@ public final class DefaultPersister implements Persister {
* <p>
* This call determines the PersistRequest.Type based on bean state and the insert flag (root persist type).
*/
private <T> PersistRequestBean<T> createRequest(T bean, Transaction t, Object parentBean, boolean insertMode) {
private <T> PersistRequestBean<T> createRequestRecurse(T bean, Transaction t, Object parentBean, boolean insertMode, boolean publish) {
BeanManager<T> mgr = getBeanManager(bean);
if (mgr == null) {
throw new PersistenceException(errNotRegistered(bean.getClass()));
}
BeanDescriptor<T> desc = mgr.getBeanDescriptor();
EntityBean entityBean = (EntityBean) bean;
// determine Insert or Update based on bean state and insert flag
PersistRequest.Type type = desc.isInsertMode(entityBean._ebean_getIntercept(), insertMode) ? Type.INSERT : Type.UPDATE;
PersistRequest.Type type;
if (publish) {
// insert if it is a new bean (as publish created it)
type = entityBean._ebean_getIntercept().isNew() ? Type.INSERT : Type.UPDATE;
} else {
// determine Insert or Update based on bean state and insert flag
type = desc.isInsertMode(entityBean._ebean_getIntercept(), insertMode) ? Type.INSERT : Type.UPDATE;
}
return createRequest(bean, t, parentBean, mgr, type, true);
}
@@ -899,11 +899,13 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
}
public Boolean isUseBeanCache() {
return useBeanCache;
// not using L2 cache for asDraft() query
return isAsDraft() ? Boolean.FALSE : useBeanCache;
}
public boolean isUseQueryCache() {
return Boolean.TRUE.equals(useQueryCache);
// not using L2 cache for asDraft() query
return !isAsDraft() && Boolean.TRUE.equals(useQueryCache);
}
public DefaultOrmQuery<T> setUseCache(boolean useBeanCache) {
@@ -917,7 +919,8 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
}
public boolean isLoadBeanCache() {
return loadBeanCache;
// not using L2 cache for asDraft() query
return !isAsDraft() && loadBeanCache;
}
public DefaultOrmQuery<T> setLoadBeanCache(boolean loadBeanCache) {