#115 - Mapping - Add support for @ElementCollection enhancement

Initial support - simple List.
This commit is contained in:
Rob Bygrave
2018-03-20 14:22:29 +13:00
parent c44931ea25
commit 74a9019535
79 changed files with 1891 additions and 805 deletions
@@ -35,7 +35,6 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
@@ -56,6 +55,8 @@ public class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfileTran
private static final Logger logger = LoggerFactory.getLogger(CQuery.class);
private static final CQueryCollectionAddNoop NOOP_ADD = new CQueryCollectionAddNoop();
/**
* The resultSet rows read.
*/
@@ -99,7 +100,7 @@ public class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfileTran
/**
* The help for the 'master' collection.
*/
private final BeanCollectionHelp<T> help;
private final CQueryCollectionAdd help;
/**
* The overall find request wrapper object.
@@ -147,7 +148,7 @@ public class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfileTran
/**
* For master detail query.
*/
private final BeanPropertyAssocMany<?> manyProperty;
private final STreePropertyAssocMany manyProperty;
private DataReader dataReader;
@@ -180,20 +181,26 @@ public class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfileTran
private long executionTimeMicros;
/**
* Flag set when findIterate is being read audited.
* Flag set when read auditing.
*/
private boolean audit;
/**
* Flag set when findIterate is being read audited meaning we log in batches.
*/
private boolean auditFindIterate;
/**
* A buffer of Ids collected for findIterate auditing.
*/
private List<Object> auditFindIterateIds;
private List<Object> auditIds;
/**
* Create the Sql select based on the request.
*/
public CQuery(OrmQueryRequest<T> request, CQueryPredicates predicates, CQueryPlan queryPlan) {
this.request = request;
this.audit = request.isAuditReads();
this.queryPlan = queryPlan;
this.query = request.getQuery();
this.queryMode = query.getMode();
@@ -220,7 +227,11 @@ public class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfileTran
this.logWhereSql = queryPlan.getLogWhereSql();
this.desc = request.getBeanDescriptor();
this.predicates = predicates;
this.help = createHelp(request);
if (lazyLoadManyProperty != null) {
this.help = NOOP_ADD;
} else {
this.help = createHelp(request);
}
this.collection = (help != null ? help.createEmptyNoParent() : null);
}
@@ -233,7 +244,7 @@ public class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfileTran
// subQuery compiled for InQueryExpression
return null;
}
return BeanCollectionHelpFactory.create(request);
return BeanCollectionHelpFactory.create(manyType, request);
}
}
@@ -374,7 +385,7 @@ public class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfileTran
*/
public void close() {
try {
if (auditFindIterateIds != null && !auditFindIterateIds.isEmpty()) {
if (auditFindIterate && auditIds != null && !auditIds.isEmpty()) {
auditIterateLogMessage();
}
} catch (Throwable e) {
@@ -510,8 +521,8 @@ public class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfileTran
}
protected EntityBean next() {
if (auditFindIterate) {
auditIterateNextBean();
if (audit) {
auditNextBean();
}
hasNextCache = false;
if (nextBean == null) {
@@ -656,7 +667,7 @@ public class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfileTran
* per SqlSelect. This can be null.
*/
@Override
public BeanPropertyAssocMany<?> getManyProperty() {
public STreePropertyAssocMany getManyProperty() {
return manyProperty;
}
@@ -747,30 +758,25 @@ public class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfileTran
*/
void auditFindMany() {
if (!collection.isEmpty()) {
if (auditIds != null && !auditIds.isEmpty()) {
// get the id values of the underlying collection
List<Object> ids = new ArrayList<>(collection.size());
Collection<T> underlyingBeans = collection.getActualDetails();
for (T underlyingBean : underlyingBeans) {
ids.add(desc.getIdForJson(underlyingBean));
}
ReadEvent futureReadEvent = query.getFutureFetchAudit();
if (futureReadEvent == null) {
// normal query execution
desc.readAuditMany(queryPlan.getAuditQueryKey(), bindLog, ids);
desc.readAuditMany(queryPlan.getAuditQueryKey(), bindLog, auditIds);
} else {
// this query was executed via findFutureList() and the prepare()
// has already been called so set the details and log
futureReadEvent.setQueryKey(queryPlan.getAuditQueryKey());
futureReadEvent.setBindLog(bindLog);
futureReadEvent.setIds(ids);
futureReadEvent.setIds(auditIds);
desc.readAuditFutureMany(futureReadEvent);
}
}
}
/**
* Indicate that read auditing is occurring on a this findIterate query.
* Indicate that read auditing is occurring on this findIterate query.
*/
void auditFindIterate() {
auditFindIterate = true;
@@ -780,21 +786,21 @@ public class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfileTran
* Send the current buffer of findIterate collected ids to the audit log.
*/
private void auditIterateLogMessage() {
desc.readAuditMany(queryPlan.getAuditQueryKey(), bindLog, auditFindIterateIds);
desc.readAuditMany(queryPlan.getAuditQueryKey(), bindLog, auditIds);
// create a new list on demand with the next bean/id
auditFindIterateIds = null;
auditIds = null;
}
/**
* Add the id to the audit id buffer and flush if needed in batches of 100.
*/
private void auditIterateNextBean() {
private void auditNextBean() {
if (auditFindIterateIds == null) {
auditFindIterateIds = new ArrayList<>(100);
if (auditIds == null) {
auditIds = new ArrayList<>(100);
}
auditFindIterateIds.add(desc.getIdForJson(nextBean));
if (auditFindIterateIds.size() >= 100) {
auditIds.add(desc.getIdForJson(nextBean));
if (auditFindIterate && auditIds.size() >= 100) {
auditIterateLogMessage();
}
}
@@ -18,7 +18,6 @@ import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.server.core.OrmQueryRequest;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.BeanProperty;
import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import io.ebeaninternal.server.deploy.BeanPropertyAssocOne;
import io.ebeaninternal.server.el.ElPropertyValue;
import io.ebeaninternal.server.persist.Binder;
@@ -524,20 +523,15 @@ class CQueryBuilder {
return rawSqlHandler.buildSql(request, predicates, query.getRawSql().getSql());
}
BeanPropertyAssocMany<?> manyProp = select.getManyProperty();
boolean useSqlLimiter = false;
StringBuilder sb = new StringBuilder(500);
String dbOrderBy = predicates.getDbOrderBy();
if (selectClause != null) {
sb.append(selectClause);
} else {
useSqlLimiter = (query.hasMaxRowsOrFirstRow() && manyProp == null);
useSqlLimiter = (query.hasMaxRowsOrFirstRow() && select.getManyProperty() == null);
if (!useSqlLimiter) {
sb.append("select ");
@@ -686,7 +680,7 @@ class CQueryBuilder {
throw new IllegalArgumentException("Illegal enum: "+ orderBy);
}
}
/**
* Append where or and based on the hasWhere flag.
*/
@@ -0,0 +1,21 @@
package io.ebeaninternal.server.query;
import io.ebean.bean.BeanCollection;
import io.ebean.bean.EntityBean;
/**
* Defines interface for adding beans to the collection which might be a List, Set or Map.
*/
public interface CQueryCollectionAdd<T> {
/**
* Create an empty collection.
*/
BeanCollection<T> createEmptyNoParent();
/**
* Add a bean to the List Set or Map.
*/
void add(BeanCollection<?> collection, EntityBean bean, boolean withCheck);
}
@@ -0,0 +1,27 @@
package io.ebeaninternal.server.query;
import io.ebean.bean.BeanCollection;
import io.ebean.bean.EntityBean;
/**
* A NOOP based CQueryCollectionAdd for use with lazy loading many queries where the
* beans loaded into the collection are added to the collection(s) of the parent(s).
*/
class CQueryCollectionAddNoop<T> implements CQueryCollectionAdd<T> {
/**
* Return null as we are not collecting the beans.
*/
@Override
public BeanCollection<T> createEmptyNoParent() {
return null;
}
/**
* Do nothing for this case.
*/
@Override
public void add(BeanCollection<?> collection, EntityBean bean, boolean withCheck) {
// do nothing
}
}
@@ -11,7 +11,6 @@ import io.ebeaninternal.metric.MetricFactory;
import io.ebeaninternal.metric.TimedMetric;
import io.ebeaninternal.server.core.OrmQueryRequest;
import io.ebeaninternal.server.core.timezone.DataTimeZone;
import io.ebeaninternal.server.deploy.BeanProperty;
import io.ebeaninternal.server.query.CQueryPlanStats.Snapshot;
import io.ebeaninternal.server.type.DataBind;
import io.ebeaninternal.server.type.DataReader;
@@ -74,7 +73,7 @@ public class CQueryPlan {
/**
* Encrypted properties required additional binding.
*/
private final BeanProperty[] encryptedProps;
private final STreeProperty[] encryptedProps;
private final CQueryPlanStats stats;
@@ -177,9 +176,8 @@ public class CQueryPlan {
DataBind bindEncryptedProperties(PreparedStatement stmt, Connection conn) throws SQLException {
DataBind dataBind = new DataBind(dataTimeZone, stmt, conn);
if (encryptedProps != null) {
for (BeanProperty encryptedProp : encryptedProps) {
String key = encryptedProp.getEncryptKey().getStringValue();
dataBind.setString(key);
for (STreeProperty encryptedProp : encryptedProps) {
dataBind.setString(encryptedProp.getEncryptKeyAsString());
}
}
return dataBind;
@@ -231,7 +231,7 @@ public class CQueryPredicates {
}
}
BeanPropertyAssocMany<?> manyProperty = request.getManyProperty();
BeanPropertyAssocMany<?> manyProperty = request.determineMany();
if (manyProperty != null) {
OrmQueryProperties chunk = query.getDetail().getChunk(manyProperty.getName(), false);
SpiExpressionList<?> filterManyExpr = chunk.getFilterMany();
@@ -0,0 +1,20 @@
package io.ebeaninternal.server.query;
public class ExtraJoin {
private final STreePropertyAssoc property;
private final boolean containsMany;
public ExtraJoin(STreePropertyAssoc property, boolean containsMany) {
this.property = property;
this.containsMany = containsMany;
}
public STreePropertyAssoc getProperty() {
return property;
}
public boolean isContainsMany() {
return containsMany;
}
}
@@ -8,10 +8,10 @@ import java.util.List;
/**
* A property in the SQL Tree.
*
* <p>
* A BeanProperty or a dynamically created property based on formula.
*/
public interface SqlTreeProperty {
public interface STreeProperty {
/**
* Return the property name.
@@ -38,6 +38,16 @@ public interface SqlTreeProperty {
*/
boolean isAggregation();
/**
* Return true if the property is a formula.
*/
boolean isFormula();
/**
* Return the encryption key as a string value (when the property is encrypted).
*/
String getEncryptKeyAsString();
/**
* Return the Expression language prefix (join path).
*/
@@ -0,0 +1,39 @@
package io.ebeaninternal.server.query;
import io.ebean.bean.EntityBean;
import io.ebeaninternal.server.deploy.DbSqlContext;
import io.ebeaninternal.server.deploy.id.IdBinder;
public interface STreePropertyAssoc extends STreeProperty {
/**
* Return the extra where clause if set.
*/
String getExtraWhere();
/**
* Return the type of the target (other side).
*/
STreeType target();
/**
* Return the IdBinder of the underlying type.
*/
IdBinder getIdBinder();
/**
* Add a Join with the given alias.
*/
SqlJoinType addJoin(SqlJoinType joinType, String alias2, String alias, DbSqlContext ctx);
/**
* Add a Join with the given prefix (determining the alias).
*/
SqlJoinType addJoin(SqlJoinType joinType, String prefix, DbSqlContext ctx);
/**
* Add a bean to the parent.
*/
void setValue(EntityBean parentBean, Object contextBean);
}
@@ -0,0 +1,45 @@
package io.ebeaninternal.server.query;
import io.ebean.bean.BeanCollection;
import io.ebean.bean.EntityBean;
import io.ebeaninternal.server.deploy.DbSqlContext;
import io.ebeaninternal.server.deploy.TableJoin;
public interface STreePropertyAssocMany extends STreePropertyAssoc {
/**
* Append exported columns to the select.
*/
void addSelectExported(DbSqlContext ctx, String prefix);
/**
* Return true if this is a ManyToMany with history.
*/
boolean isManyToManyWithHistory();
/**
* Return a reference collection.
*/
BeanCollection<?> createReferenceIfNull(EntityBean localBean);
/**
* Return true if the property has a join table.
*/
boolean hasJoinTable();
/**
* Return the intersection table join.
*/
TableJoin getIntersectionTableJoin();
/**
* Add a bean to the collection.
*/
void addBeanToCollectionWithCreate(EntityBean contextParent, EntityBean detailBean, boolean withCheck);
/**
* Return true if the property is excluded from history.
*/
boolean isExcludedFromHistory();
}
@@ -0,0 +1,16 @@
package io.ebeaninternal.server.query;
import io.ebeaninternal.server.type.ScalarType;
public interface STreePropertyAssocOne extends STreePropertyAssoc {
/**
* Return true if the property is an Id.
*/
boolean isAssocId();
/**
* Return the scalar type of the associated id property.
*/
ScalarType<?> getIdScalarType();
}
@@ -0,0 +1,136 @@
package io.ebeaninternal.server.query;
import io.ebean.bean.EntityBean;
import io.ebean.bean.PersistenceContext;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.server.deploy.DbReadContext;
import io.ebeaninternal.server.deploy.InheritInfo;
import io.ebeaninternal.server.deploy.id.IdBinder;
/**
* Bean type interface for Sql query tree.
*/
public interface STreeType {
/**
* Return the bean short name.
*/
String getName();
/**
* Return true if the underlying type has an Id property.
*/
boolean hasId();
/**
* Return true if the type is for ElementCollection (not mapped to an entity type/class).
*/
boolean isElementType();
/**
* Return true if the type uses soft delete.
*/
boolean isSoftDelete();
/**
* Return true if the type uses history.
*/
boolean isHistorySupport();
/**
* Return true if the type is RawSql based.
*/
boolean isRawSqlBased();
/**
* Return the soft delete predicate using the given table alias.
*/
String getSoftDeletePredicate(String baseTableAlias);
/**
* Return the scalar properties.
*/
STreeProperty[] propsBaseScalar();
/**
* Return the embedded bean properties.
*/
STreePropertyAssoc[] propsEmbedded();
/**
* Return the associated one properties.
*/
STreePropertyAssocOne[] propsOne();
/**
* Return the associated many properties.
*/
STreePropertyAssocMany[] propsMany();
/**
* Return the inheritance information for this type.
*/
InheritInfo getInheritInfo();
/**
* Return the IdBinder for this type.
*/
IdBinder getIdBinder();
/**
* Create a new entity bean instance.
*/
EntityBean createEntityBean();
/**
* Put the entity bean into the persistence context.
*/
Object contextPutIfAbsent(PersistenceContext persistenceContext, Object id, EntityBean localBean);
/**
* Set draft status on the entity bean.
*/
void setDraft(EntityBean localBean);
/**
* Invoke any post load listeners.
*/
void postLoad(Object localBean);
/**
* Return the base table to use given the temporalMode.
*/
String getBaseTable(SpiQuery.TemporalMode temporalMode);
/**
* Return true if the given path is an embedded bean.
*/
boolean isEmbeddedPath(String propertyPath);
/**
* Return the bean property traversing the object graph and taking into account inheritance.
*/
STreeProperty findPropertyFromPath(String property);
/**
* Find a known property.
*/
STreeProperty findProperty(String propName);
/**
* Find and return property allowing for dynamic formula properties.
*/
STreeProperty findPropertyWithDynamic(String baseName);
/**
* Return an extra join if the property path requires it.
*/
ExtraJoin extraJoin(String propertyPath);
/**
* Load the property taking into account inheritance.
*/
void inheritanceLoad(SqlBeanLoad sqlBeanLoad, STreeProperty property, DbReadContext ctx);
}
@@ -1,8 +1,6 @@
package io.ebeaninternal.server.query;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.server.deploy.BeanProperty;
import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import java.util.ArrayList;
import java.util.List;
@@ -18,7 +16,7 @@ class SqlTree {
/**
* Property if resultSet contains master and detail rows.
*/
private final BeanPropertyAssocMany<?> manyProperty;
private final STreePropertyAssocMany manyProperty;
private final Set<String> includes;
@@ -38,7 +36,7 @@ class SqlTree {
/**
* Encrypted Properties require additional binding.
*/
private final BeanProperty[] encryptedProps;
private final STreeProperty[] encryptedProps;
/**
* Where clause for inheritance.
@@ -51,7 +49,7 @@ class SqlTree {
* Create the SqlSelectClause.
*/
SqlTree(String summary, SqlTreeNode rootNode, String distinctOn, String selectSql, String fromSql, String groupBy, String inheritanceWhereSql,
BeanProperty[] encryptedProps, BeanPropertyAssocMany<?> manyProperty, Set<String> includes, boolean includeJoins) {
STreeProperty[] encryptedProps, STreePropertyAssocMany manyProperty, Set<String> includes, boolean includeJoins) {
this.summary = summary;
this.rootNode = rootNode;
@@ -147,11 +145,11 @@ class SqlTree {
* Return the property that is associated with the many. There can only be one
* per SqlSelect. This can be null.
*/
BeanPropertyAssocMany<?> getManyProperty() {
STreePropertyAssocMany getManyProperty() {
return manyProperty;
}
BeanProperty[] getEncryptedProps() {
STreeProperty[] getEncryptedProps() {
return encryptedProps;
}
@@ -1,17 +1,14 @@
package io.ebeaninternal.server.query;
import io.ebean.util.SplitName;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.el.ElPropertyDeploy;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.persistence.PersistenceException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Special Map of the logical property joins to table alias.
@@ -61,16 +58,11 @@ class SqlTreeAlias {
/**
* Add joins.
*/
public void addJoin(Set<String> propJoins, BeanDescriptor<?> desc) {
public void addJoin(Set<String> propJoins, STreeType desc) {
if (propJoins != null) {
for (String propJoin : propJoins) {
ElPropertyDeploy elProp = desc.getElPropertyDeploy(propJoin);
if (elProp == null) {
throw new PersistenceException("Invalid path " + propJoin + " from " + desc.getFullName());
} else if (elProp.getBeanProperty().isEmbedded()) {
if (desc.isEmbeddedPath(propJoin)) {
addEmbeddedPropertyJoin(propJoin);
} else {
addPropertyJoin(propJoin, joinProps);
}
@@ -6,14 +6,8 @@ import io.ebeaninternal.api.PropertyJoin;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.api.SpiQuery.Type;
import io.ebeaninternal.server.core.OrmQueryRequest;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.BeanProperty;
import io.ebeaninternal.server.deploy.BeanPropertyAssoc;
import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import io.ebeaninternal.server.deploy.BeanPropertyAssocOne;
import io.ebeaninternal.server.deploy.InheritInfo;
import io.ebeaninternal.server.deploy.TableJoin;
import io.ebeaninternal.server.el.ElPropertyValue;
import io.ebeaninternal.server.querydefn.OrmQueryDetail;
import io.ebeaninternal.server.querydefn.OrmQueryProperties;
import org.slf4j.Logger;
@@ -37,7 +31,7 @@ public final class SqlTreeBuilder {
private final SpiQuery<?> query;
private final BeanDescriptor<?> desc;
private final STreeType desc;
private final OrmQueryDetail queryDetail;
@@ -51,7 +45,7 @@ public final class SqlTreeBuilder {
/**
* Property if resultSet contains master and detail rows.
*/
private BeanPropertyAssocMany<?> manyProperty;
private STreePropertyAssocMany manyProperty;
private final SqlTreeAlias alias;
@@ -141,7 +135,7 @@ public final class SqlTreeBuilder {
String fromSql = null;
String inheritanceWhereSql = null;
String groupBy = null;
BeanProperty[] encryptedProps = null;
STreeProperty[] encryptedProps = null;
if (!rawSql) {
selectSql = buildSelectClause();
fromSql = buildFromClause();
@@ -233,7 +227,7 @@ public final class SqlTreeBuilder {
return ctx.getContent();
}
private void buildRoot(BeanDescriptor<?> desc) {
private void buildRoot(STreeType desc) {
rootNode = buildSelectChain(null, null, desc, null);
@@ -253,26 +247,24 @@ public final class SqlTreeBuilder {
* Recursively build the query tree depending on what leaves in the tree
* should be included.
*/
private SqlTreeNode buildSelectChain(String prefix, BeanPropertyAssoc<?> prop,
BeanDescriptor<?> desc, List<SqlTreeNode> joinList) {
private SqlTreeNode buildSelectChain(String prefix, STreePropertyAssoc prop,
STreeType desc, List<SqlTreeNode> joinList) {
List<SqlTreeNode> myJoinList = new ArrayList<>();
BeanPropertyAssocOne<?>[] ones = desc.propertiesOne();
for (BeanPropertyAssocOne<?> one : ones) {
for (STreePropertyAssocOne one : desc.propsOne()) {
String propPrefix = SplitName.add(prefix, one.getName());
if (isIncludeBean(propPrefix)) {
selectIncludes.add(propPrefix);
buildSelectChain(propPrefix, one, one.getTargetDescriptor(), myJoinList);
buildSelectChain(propPrefix, one, one.target(), myJoinList);
}
}
BeanPropertyAssocMany<?>[] manys = desc.propertiesMany();
for (BeanPropertyAssocMany<?> many : manys) {
for (STreePropertyAssocMany many : desc.propsMany()) {
String propPrefix = SplitName.add(prefix, many.getName());
if (isIncludeMany(propPrefix, many)) {
selectIncludes.add(propPrefix);
buildSelectChain(propPrefix, many, many.getTargetDescriptor(), myJoinList);
buildSelectChain(propPrefix, many, many.target(), myJoinList);
}
}
@@ -304,24 +296,24 @@ public final class SqlTreeBuilder {
Collection<PropertyJoin> includes = manyWhereJoins.getPropertyJoins();
for (PropertyJoin joinProp : includes) {
BeanPropertyAssoc<?> beanProperty = (BeanPropertyAssoc<?>) desc.getBeanPropertyFromPath(joinProp.getProperty());
STreePropertyAssoc beanProperty = (STreePropertyAssoc) desc.findPropertyFromPath(joinProp.getProperty());
SqlTreeNodeManyWhereJoin nodeJoin = new SqlTreeNodeManyWhereJoin(joinProp.getProperty(), beanProperty, joinProp.getSqlJoinType());
myJoinList.add(nodeJoin);
}
}
private SqlTreeNode buildNode(String prefix, BeanPropertyAssoc<?> prop, BeanDescriptor<?> desc, List<SqlTreeNode> myList, SqlTreeProperties props) {
private SqlTreeNode buildNode(String prefix, STreePropertyAssoc prop, STreeType desc, List<SqlTreeNode> myList, SqlTreeProperties props) {
if (prefix == null) {
buildExtraJoins(desc, myList);
// Optional many property for lazy loading query
BeanPropertyAssocMany<?> lazyLoadMany = (query == null) ? null : query.getLazyLoadMany();
STreePropertyAssocMany lazyLoadMany = (query == null) ? null : query.getLazyLoadMany();
boolean withId = !rawNoId && !subQuery && (query == null || query.isWithId());
return new SqlTreeNodeRoot(desc, props, myList, withId, includeJoin, lazyLoadMany, temporalMode, disableLazyLoad);
} else if (prop instanceof BeanPropertyAssocMany<?>) {
return new SqlTreeNodeManyRoot(prefix, (BeanPropertyAssocMany<?>) prop, props, myList, temporalMode, disableLazyLoad);
} else if (prop instanceof STreePropertyAssocMany) {
return new SqlTreeNodeManyRoot(prefix, (STreePropertyAssocMany) prop, props, myList, temporalMode, disableLazyLoad);
} else {
// do not read Id on child beans (e.g. when used with fetch())
@@ -334,7 +326,7 @@ public final class SqlTreeBuilder {
* Build extra joins to support properties used in where clause but not
* already in select clause.
*/
private void buildExtraJoins(BeanDescriptor<?> desc, List<SqlTreeNode> myList) {
private void buildExtraJoins(STreeType desc, List<SqlTreeNode> myList) {
if (rawSql) {
return;
@@ -383,25 +375,25 @@ public final class SqlTreeBuilder {
* This means it can included individual properties of an embedded bean.
* </p>
*/
private void addPropertyToSubQuery(SqlTreeProperties selectProps, BeanDescriptor<?> desc, String propName) {
private void addPropertyToSubQuery(SqlTreeProperties selectProps, STreeType desc, String propName) {
BeanProperty p = desc.findBeanProperty(propName);
STreeProperty p = desc.findProperty(propName);
if (p == null) {
logger.error("property [" + propName + "]not found on " + desc + " for query - excluding it.");
} else if (p instanceof BeanPropertyAssoc<?> && p.isEmbedded()) {
} else if (p instanceof STreePropertyAssoc && p.isEmbedded()) {
// if the property is embedded we need to lookup the real column name
int pos = propName.indexOf('.');
if (pos > -1) {
String name = propName.substring(pos + 1);
p = ((BeanPropertyAssoc<?>) p).getTargetDescriptor().findBeanProperty(name);
p = ((STreePropertyAssoc) p).target().findProperty(name);
}
}
selectProps.add(p);
}
private void addProperty(SqlTreeProperties selectProps, BeanDescriptor<?> desc,
private void addProperty(SqlTreeProperties selectProps, STreeType desc,
OrmQueryProperties queryProps, String propName) {
if (subQuery) {
@@ -418,7 +410,7 @@ public final class SqlTreeBuilder {
// make sure we only included the base/embedded bean once
if (!selectProps.containsProperty(baseName)) {
SqlTreeProperty p = desc.findSqlTreeProperty(baseName);
STreeProperty p = desc.findPropertyWithDynamic(baseName);
if (p == null) {
logger.error("property [" + propName + "] not found on " + desc + " for query - excluding it.");
@@ -436,17 +428,17 @@ public final class SqlTreeBuilder {
} else {
// find the property including searching the
// sub class hierarchy if required
SqlTreeProperty p = desc.findSqlTreeProperty(propName);
STreeProperty p = desc.findPropertyWithDynamic(propName);
if (p == null) {
logger.error("property [" + propName + "] not found on " + desc + " for query - excluding it.");
p = desc.findBeanProperty("id");
p = desc.findProperty("id");
selectProps.add(p);
} else if (p.isId() && excludeIdProperty()) {
// do not bother to include id for normal queries as the
// id is always added (except for subQueries)
} else if (p instanceof BeanPropertyAssoc<?>) {
} else if (p instanceof STreePropertyAssoc) {
// need to check if this property should be
// excluded. This occurs when this property is
// included as a bean join. With a bean join
@@ -463,7 +455,7 @@ public final class SqlTreeBuilder {
}
}
private SqlTreeProperties getBaseSelectPartial(BeanDescriptor<?> desc, OrmQueryProperties queryProps) {
private SqlTreeProperties getBaseSelectPartial(STreeType desc, OrmQueryProperties queryProps) {
SqlTreeProperties selectProps = new SqlTreeProperties();
selectProps.setReadOnly(queryProps.isReadOnly());
@@ -484,7 +476,7 @@ public final class SqlTreeBuilder {
return selectProps;
}
private SqlTreeProperties getBaseSelect(BeanDescriptor<?> desc, OrmQueryProperties queryProps) {
private SqlTreeProperties getBaseSelect(STreeType desc, OrmQueryProperties queryProps) {
boolean partial = queryProps != null && !queryProps.allProperties();
if (partial) {
@@ -495,17 +487,16 @@ public final class SqlTreeBuilder {
selectProps.setAllProperties();
// normal simple properties of the bean
selectProps.add(desc.propertiesBaseScalar());
selectProps.add(desc.propertiesEmbedded());
selectProps.add(desc.propsBaseScalar());
selectProps.add(desc.propsEmbedded());
BeanPropertyAssocOne<?>[] propertiesOne = desc.propertiesOne();
for (BeanPropertyAssocOne<?> aPropertiesOne : propertiesOne) {
for (STreePropertyAssocOne propertyAssocOne : desc.propsOne()) {
//noinspection StatementWithEmptyBody
if (queryProps != null && queryProps.isIncludedBeanJoin(aPropertiesOne.getName())) {
if (queryProps != null && queryProps.isIncludedBeanJoin(propertyAssocOne.getName())) {
// if it is a joined bean... then don't add the property
// as it will have its own entire Node in the SqlTree
} else {
selectProps.add(aPropertiesOne);
selectProps.add(propertyAssocOne);
}
}
@@ -521,7 +512,7 @@ public final class SqlTreeBuilder {
/**
* Return true if this many node should be included in the query.
*/
private boolean isIncludeMany(String propName, BeanPropertyAssocMany<?> manyProp) {
private boolean isIncludeMany(String propName, STreePropertyAssocMany manyProp) {
if (queryDetail.isJoinsEmpty()) {
return false;
@@ -588,9 +579,9 @@ public final class SqlTreeBuilder {
*/
private final Map<String, SqlTreeNodeExtraJoin> rootRegister = new HashMap<>();
private final BeanDescriptor<?> desc;
private final STreeType desc;
private IncludesDistiller(BeanDescriptor<?> desc, Set<String> selectIncludes,
private IncludesDistiller(STreeType desc, Set<String> selectIncludes,
Set<String> predicateIncludes) {
this.desc = desc;
this.selectIncludes = selectIncludes;
@@ -645,25 +636,14 @@ public final class SqlTreeBuilder {
*/
private SqlTreeNodeExtraJoin createJoinLeaf(String propertyName) {
ElPropertyValue elGetValue = desc.getElGetValue(propertyName);
if (elGetValue == null) {
// this can occur for master detail queries
// with concatenated keys (so not an error now)
ExtraJoin extra = desc.extraJoin(propertyName);
if (extra == null) {
return null;
}
BeanProperty beanProperty = elGetValue.getBeanProperty();
if (beanProperty instanceof BeanPropertyAssoc<?>) {
BeanPropertyAssoc<?> assocProp = (BeanPropertyAssoc<?>) beanProperty;
if (assocProp.isEmbedded()) {
// no extra join required for embedded beans
return null;
}
SqlTreeNodeExtraJoin extraJoin = new SqlTreeNodeExtraJoin(propertyName, assocProp, elGetValue.containsMany());
} else {
SqlTreeNodeExtraJoin extraJoin = new SqlTreeNodeExtraJoin(propertyName, extra.getProperty(), extra.isContainsMany());
joinRegister.put(propertyName, extraJoin);
return extraJoin;
}
return null;
}
/**
@@ -674,10 +654,8 @@ public final class SqlTreeBuilder {
* not specified and is implicitly created.
* </p>
*/
private SqlTreeNodeExtraJoin findExtraJoinRoot(String includeProp,
SqlTreeNodeExtraJoin childJoin) {
private SqlTreeNodeExtraJoin findExtraJoinRoot(String includeProp, SqlTreeNodeExtraJoin childJoin) {
while (true) {
int dotPos = includeProp.lastIndexOf('.');
if (dotPos == -1) {
// no parent possible(parent is root)
@@ -9,11 +9,6 @@ import io.ebean.util.SplitName;
import io.ebean.util.StringHelper;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.api.SpiQuery.Mode;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.BeanProperty;
import io.ebeaninternal.server.deploy.BeanPropertyAssoc;
import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import io.ebeaninternal.server.deploy.BeanPropertyAssocOne;
import io.ebeaninternal.server.deploy.DbReadContext;
import io.ebeaninternal.server.deploy.DbSqlContext;
import io.ebeaninternal.server.deploy.InheritInfo;
@@ -34,7 +29,7 @@ class SqlTreeNodeBean implements SqlTreeNode {
private static final SqlTreeNode[] NO_CHILDREN = new SqlTreeNode[0];
protected final BeanDescriptor<?> desc;
protected final STreeType desc;
protected final IdBinder idBinder;
@@ -48,14 +43,14 @@ class SqlTreeNodeBean implements SqlTreeNode {
*/
private final boolean partialObject;
protected final SqlTreeProperty[] properties;
protected final STreeProperty[] properties;
/**
* Extra where clause added by Where annotation on associated many.
*/
private final String extraWhere;
private final BeanPropertyAssoc<?> nodeBeanProp;
private final STreePropertyAssoc nodeBeanProp;
/**
* False if report bean and has no id property.
@@ -70,7 +65,7 @@ class SqlTreeNodeBean implements SqlTreeNode {
private final Map<String, String> pathMap;
final BeanPropertyAssocMany<?> lazyLoadParent;
final STreePropertyAssocMany lazyLoadParent;
final SpiQuery.TemporalMode temporalMode;
@@ -92,29 +87,29 @@ class SqlTreeNodeBean implements SqlTreeNode {
/**
* Construct for leaf node.
*/
SqlTreeNodeBean(String prefix, BeanPropertyAssoc<?> beanProp, SqlTreeProperties props,
SqlTreeNodeBean(String prefix, STreePropertyAssoc beanProp, SqlTreeProperties props,
List<SqlTreeNode> myChildren, boolean withId, SpiQuery.TemporalMode temporalMode, boolean disableLazyLoad) {
this(prefix, beanProp, beanProp.getTargetDescriptor(), props, myChildren, withId, null, temporalMode, disableLazyLoad);
this(prefix, beanProp, beanProp.target(), props, myChildren, withId, null, temporalMode, disableLazyLoad);
}
/**
* Construct for root node.
*/
SqlTreeNodeBean(BeanDescriptor<?> desc, SqlTreeProperties props, List<SqlTreeNode> myList, boolean withId,
BeanPropertyAssocMany<?> many, SpiQuery.TemporalMode temporalMode, boolean disableLazyLoad) {
SqlTreeNodeBean(STreeType desc, SqlTreeProperties props, List<SqlTreeNode> myList, boolean withId,
STreePropertyAssocMany many, SpiQuery.TemporalMode temporalMode, boolean disableLazyLoad) {
this(null, null, desc, props, myList, withId, many, temporalMode, disableLazyLoad);
}
/**
* Create with the appropriate node.
*/
private SqlTreeNodeBean(String prefix, BeanPropertyAssoc<?> beanProp, BeanDescriptor<?> desc, SqlTreeProperties props,
List<SqlTreeNode> myChildren, boolean withId, BeanPropertyAssocMany<?> lazyLoadParent,
private SqlTreeNodeBean(String prefix, STreePropertyAssoc beanProp, STreeType desc, SqlTreeProperties props,
List<SqlTreeNode> myChildren, boolean withId, STreePropertyAssocMany lazyLoadParent,
SpiQuery.TemporalMode temporalMode, boolean disableLazyLoad) {
this.lazyLoadParent = lazyLoadParent;
this.lazyLoadParentIdBinder = (lazyLoadParent == null) ? null : lazyLoadParent.getBeanDescriptor().getIdBinder();
this.lazyLoadParentIdBinder = (lazyLoadParent == null) ? null : lazyLoadParent.getIdBinder();
this.prefix = prefix;
this.desc = desc;
this.inheritInfo = desc.getInheritInfo();
@@ -129,7 +124,7 @@ class SqlTreeNodeBean implements SqlTreeNode {
this.aggregationRoot = props.isAggregationRoot();
// the bean has an Id property and we want to use it
this.readId = !aggregationRoot && withId && (desc.getIdProperty() != null);
this.readId = !aggregationRoot && withId && desc.hasId();
this.disableLazyLoad = disableLazyLoad || !readId || desc.isRawSqlBased() || temporalVersions;
this.partialObject = props.isPartialObject();
@@ -150,25 +145,22 @@ class SqlTreeNodeBean implements SqlTreeNode {
// if we have also no children, NPE happens anyway.
return children[0].getSingleAttributeScalarType();
}
if (properties[0] instanceof BeanPropertyAssocOne<?>) {
BeanPropertyAssocOne<?> assocOne = (BeanPropertyAssocOne<?>)properties[0];
if (properties[0] instanceof STreePropertyAssocOne) {
STreePropertyAssocOne assocOne = (STreePropertyAssocOne)properties[0];
if (assocOne.isAssocId()) {
return assocOne.getTargetDescriptor().getIdProperty().getScalarType();
return assocOne.getIdScalarType();
}
}
return properties[0].getScalarType();
}
private Map<String, String> createPathMap(String prefix, BeanDescriptor<?> desc) {
BeanPropertyAssocMany<?>[] manys = desc.propertiesMany();
private Map<String, String> createPathMap(String prefix, STreeType desc) {
HashMap<String, String> m = new HashMap<>();
for (BeanPropertyAssocMany<?> many : manys) {
for (STreePropertyAssocMany many : desc.propsMany()) {
String name = many.getName();
m.put(name, getPath(prefix, name));
}
return m;
}
@@ -189,7 +181,7 @@ class SqlTreeNodeBean implements SqlTreeNode {
}
idBinder.buildRawSqlSelectChain(prefix, selectChain);
}
for (SqlTreeProperty property : properties) {
for (STreeProperty property : properties) {
property.buildRawSqlSelectChain(prefix, selectChain);
}
// recursively continue reading...
@@ -228,7 +220,7 @@ class SqlTreeNodeBean implements SqlTreeNode {
}
Class<?> localType;
BeanDescriptor<?> localDesc;
STreeType localDesc;
IdBinder localIdBinder;
EntityBean localBean;
@@ -292,21 +284,16 @@ class SqlTreeNodeBean implements SqlTreeNode {
if (inheritInfo == null) {
// normal behavior with no inheritance
for (SqlTreeProperty property : properties) {
for (STreeProperty property : properties) {
property.load(sqlBeanLoad);
}
} else {
// take account of inheritance and due to subclassing approach
// need to get a 'local' version of the property
for (SqlTreeProperty property : properties) {
for (STreeProperty property : properties) {
// get a local version of the BeanProperty
BeanProperty p = localDesc.getBeanProperty(property.getName());
if (p != null) {
p.load(sqlBeanLoad);
} else {
property.loadIgnore(ctx);
}
localDesc.inheritanceLoad(sqlBeanLoad, property, ctx);
}
}
@@ -374,6 +361,9 @@ class SqlTreeNodeBean implements SqlTreeNode {
if (!readId || temporalVersions) {
// a bean with no Id (never found in context)
if (lazyLoadParentId != null && desc.isElementType()) {
ctx.setLazyLoadedChildBean(localBean, lazyLoadParentId);
}
return localBean;
} else {
@@ -388,13 +378,12 @@ class SqlTreeNodeBean implements SqlTreeNode {
* Create lazy loading proxies for the Many's except for the one that is
* included in the actual query.
*/
private void createListProxies(BeanDescriptor<?> localDesc, DbReadContext ctx, EntityBean localBean, boolean disableLazyLoad) {
private void createListProxies(STreeType localDesc, DbReadContext ctx, EntityBean localBean, boolean disableLazyLoad) {
BeanPropertyAssocMany<?> fetchedMany = ctx.getManyProperty();
STreePropertyAssocMany fetchedMany = ctx.getManyProperty();
// load the List/Set/Map proxy objects (deferred fetching of lists)
BeanPropertyAssocMany<?>[] manys = localDesc.propertiesMany();
for (BeanPropertyAssocMany<?> many : manys) {
for (STreePropertyAssocMany many : localDesc.propsMany()) {
if (fetchedMany == null || !fetchedMany.equals(many)) {
// create a proxy for the many (deferred fetching)
@@ -419,7 +408,7 @@ class SqlTreeNodeBean implements SqlTreeNode {
if (readId) {
appendSelectId(ctx, idBinder.getBeanProperty());
}
for (SqlTreeProperty property : properties) {
for (STreeProperty property : properties) {
if (!property.isAggregation()) {
property.appendSelect(ctx, subQuery);
}
@@ -486,14 +475,13 @@ class SqlTreeNodeBean implements SqlTreeNode {
/**
* Append the properties to the buffer.
*/
private void appendSelect(DbSqlContext ctx, boolean subQuery, SqlTreeProperty[] props) {
for (SqlTreeProperty prop : props) {
private void appendSelect(DbSqlContext ctx, boolean subQuery, STreeProperty[] props) {
for (STreeProperty prop : props) {
prop.appendSelect(ctx, subQuery);
}
}
protected void appendSelectId(DbSqlContext ctx, BeanProperty prop) {
protected void appendSelectId(DbSqlContext ctx, STreeProperty prop) {
if (prop != null) {
prop.appendSelect(ctx, false);
}
@@ -546,7 +534,7 @@ class SqlTreeNodeBean implements SqlTreeNode {
// join and return SqlJoinType to use for child joins
joinType = appendFromBaseTable(ctx, joinType);
for (SqlTreeProperty property : properties) {
for (STreeProperty property : properties) {
// usually nothing... except for 1-1 Exported
property.appendFrom(ctx, joinType);
}
@@ -601,8 +589,8 @@ class SqlTreeNodeBean implements SqlTreeNode {
private SqlJoinType appendFromAsJoin(DbSqlContext ctx, SqlJoinType joinType) {
if (nodeBeanProp instanceof BeanPropertyAssocMany<?>) {
BeanPropertyAssocMany<?> manyProp = (BeanPropertyAssocMany<?>) nodeBeanProp;
if (nodeBeanProp instanceof STreePropertyAssocMany) {
STreePropertyAssocMany manyProp = (STreePropertyAssocMany) nodeBeanProp;
if (manyProp.hasJoinTable()) {
String alias = ctx.getTableAlias(prefix);
@@ -619,7 +607,6 @@ class SqlTreeNodeBean implements SqlTreeNode {
return nodeBeanProp.addJoin(joinType, alias2, alias, ctx);
}
}
return nodeBeanProp.addJoin(joinType, prefix, ctx);
@@ -4,14 +4,11 @@ import io.ebean.Version;
import io.ebean.bean.EntityBean;
import io.ebean.util.SplitName;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.server.deploy.BeanPropertyAssoc;
import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import io.ebeaninternal.server.deploy.DbReadContext;
import io.ebeaninternal.server.deploy.DbSqlContext;
import io.ebeaninternal.server.deploy.TableJoin;
import io.ebeaninternal.server.type.ScalarType;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
@@ -25,7 +22,7 @@ import java.util.List;
*/
class SqlTreeNodeExtraJoin implements SqlTreeNode {
private final BeanPropertyAssoc<?> assocBeanProperty;
private final STreePropertyAssoc assocBeanProperty;
private final String prefix;
@@ -35,11 +32,11 @@ class SqlTreeNodeExtraJoin implements SqlTreeNode {
private List<SqlTreeNodeExtraJoin> children;
SqlTreeNodeExtraJoin(String prefix, BeanPropertyAssoc<?> assocBeanProperty, boolean pathContainsMany) {
SqlTreeNodeExtraJoin(String prefix, STreePropertyAssoc assocBeanProperty, boolean pathContainsMany) {
this.prefix = prefix;
this.assocBeanProperty = assocBeanProperty;
this.pathContainsMany = pathContainsMany;
this.manyJoin = assocBeanProperty instanceof BeanPropertyAssocMany<?>;
this.manyJoin = assocBeanProperty instanceof STreePropertyAssocMany;
}
@Override
@@ -103,8 +100,8 @@ class SqlTreeNodeExtraJoin implements SqlTreeNode {
boolean manyToMany = false;
if (assocBeanProperty instanceof BeanPropertyAssocMany<?>) {
BeanPropertyAssocMany<?> manyProp = (BeanPropertyAssocMany<?>) assocBeanProperty;
if (assocBeanProperty instanceof STreePropertyAssocMany) {
STreePropertyAssocMany manyProp = (STreePropertyAssocMany) assocBeanProperty;
if (manyProp.hasJoinTable()) {
manyToMany = true;
@@ -127,7 +124,7 @@ class SqlTreeNodeExtraJoin implements SqlTreeNode {
}
if (!manyToMany) {
if (assocBeanProperty.isFormula()) {
// add joins for formula beans
// add joins for formula beans
assocBeanProperty.appendFrom(ctx, joinType);
}
joinType = assocBeanProperty.addJoin(joinType, prefix, ctx);
@@ -164,7 +161,7 @@ class SqlTreeNodeExtraJoin implements SqlTreeNode {
* Does nothing.
*/
@Override
public EntityBean load(DbReadContext ctx, EntityBean localBean, EntityBean parentBean) throws SQLException {
public EntityBean load(DbReadContext ctx, EntityBean localBean, EntityBean parentBean) {
return null;
}
@@ -172,7 +169,7 @@ class SqlTreeNodeExtraJoin implements SqlTreeNode {
* Does nothing.
*/
@Override
public <T> Version<T> loadVersion(DbReadContext ctx) throws SQLException {
public <T> Version<T> loadVersion(DbReadContext ctx) {
return null;
}
@@ -2,7 +2,6 @@ package io.ebeaninternal.server.query;
import io.ebean.bean.EntityBean;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import io.ebeaninternal.server.deploy.DbReadContext;
import io.ebeaninternal.server.deploy.DbSqlContext;
@@ -11,9 +10,9 @@ import java.util.List;
final class SqlTreeNodeManyRoot extends SqlTreeNodeBean {
private final BeanPropertyAssocMany<?> manyProp;
private final STreePropertyAssocMany manyProp;
SqlTreeNodeManyRoot(String prefix, BeanPropertyAssocMany<?> prop, SqlTreeProperties props, List<SqlTreeNode> myList,
SqlTreeNodeManyRoot(String prefix, STreePropertyAssocMany prop, SqlTreeProperties props, List<SqlTreeNode> myList,
SpiQuery.TemporalMode temporalMode, boolean disableLazyLoad) {
super(prefix, prop, props, myList, true, temporalMode, disableLazyLoad);
this.manyProp = prop;
@@ -4,15 +4,11 @@ import io.ebean.Version;
import io.ebean.bean.EntityBean;
import io.ebean.util.SplitName;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.server.deploy.BeanPropertyAssoc;
import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import io.ebeaninternal.server.deploy.BeanPropertyAssocOne;
import io.ebeaninternal.server.deploy.DbReadContext;
import io.ebeaninternal.server.deploy.DbSqlContext;
import io.ebeaninternal.server.deploy.TableJoin;
import io.ebeaninternal.server.type.ScalarType;
import java.sql.SQLException;
import java.util.List;
/**
@@ -24,15 +20,14 @@ class SqlTreeNodeManyWhereJoin implements SqlTreeNode {
private final String prefix;
private final BeanPropertyAssoc<?> nodeBeanProp;
private final STreePropertyAssoc nodeBeanProp;
/**
* The many where join which is either INNER or OUTER.
*/
private final SqlJoinType manyJoinType;
SqlTreeNodeManyWhereJoin(String prefix, BeanPropertyAssoc<?> prop, SqlJoinType manyJoinType) {
SqlTreeNodeManyWhereJoin(String prefix, STreePropertyAssoc prop, SqlJoinType manyJoinType) {
this.nodeBeanProp = prop;
this.prefix = prefix;
this.manyJoinType = manyJoinType;
@@ -86,16 +81,16 @@ class SqlTreeNodeManyWhereJoin implements SqlTreeNode {
* Join to base table for this node. This includes a join to the
* intersection table if this is a ManyToMany node.
*/
void appendFromBaseTable(DbSqlContext ctx, SqlJoinType joinType) {
private void appendFromBaseTable(DbSqlContext ctx, SqlJoinType joinType) {
String alias = ctx.getTableAliasManyWhere(prefix);
String parentAlias = ctx.getTableAliasManyWhere(parentPrefix);
if (nodeBeanProp instanceof BeanPropertyAssocOne<?>) {
if (nodeBeanProp instanceof STreePropertyAssocOne) {
nodeBeanProp.addJoin(joinType, parentAlias, alias, ctx);
} else {
BeanPropertyAssocMany<?> manyProp = (BeanPropertyAssocMany<?>) nodeBeanProp;
STreePropertyAssocMany manyProp = (STreePropertyAssocMany) nodeBeanProp;
if (!manyProp.hasJoinTable()) {
manyProp.addJoin(joinType, parentAlias, alias, ctx);
@@ -125,13 +120,13 @@ class SqlTreeNodeManyWhereJoin implements SqlTreeNode {
}
@Override
public EntityBean load(DbReadContext ctx, EntityBean localBean, EntityBean parentBean) throws SQLException {
public EntityBean load(DbReadContext ctx, EntityBean localBean, EntityBean parentBean) {
// nothing to do here
return null;
}
@Override
public <T> Version<T> loadVersion(DbReadContext ctx) throws SQLException {
public <T> Version<T> loadVersion(DbReadContext ctx) {
// nothing to do here
return null;
}
@@ -1,8 +1,6 @@
package io.ebeaninternal.server.query;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import io.ebeaninternal.server.deploy.DbSqlContext;
import io.ebeaninternal.server.deploy.TableJoin;
@@ -18,8 +16,8 @@ final class SqlTreeNodeRoot extends SqlTreeNodeBean {
/**
* Specify for SqlSelect to include an Id property or not.
*/
SqlTreeNodeRoot(BeanDescriptor<?> desc, SqlTreeProperties props, List<SqlTreeNode> myList, boolean withId,
TableJoin includeJoin, BeanPropertyAssocMany<?> many, SpiQuery.TemporalMode temporalMode, boolean disableLazyLoad) {
SqlTreeNodeRoot(STreeType desc, SqlTreeProperties props, List<SqlTreeNode> myList, boolean withId,
TableJoin includeJoin, STreePropertyAssocMany many, SpiQuery.TemporalMode temporalMode, boolean disableLazyLoad) {
super(desc, props, myList, withId, many, temporalMode, disableLazyLoad);
this.includeJoin = includeJoin;
@@ -20,7 +20,7 @@ public class SqlTreeProperties {
/**
* The bean properties in order.
*/
private final List<SqlTreeProperty> propsList = new ArrayList<>();
private final List<STreeProperty> propsList = new ArrayList<>();
/**
* Maintain a list of property names to detect embedded bean additions.
@@ -40,17 +40,17 @@ public class SqlTreeProperties {
return propNames.contains(propName);
}
public void add(SqlTreeProperty[] props) {
public void add(STreeProperty[] props) {
propsList.addAll(Arrays.asList(props));
}
public void add(SqlTreeProperty prop) {
public void add(STreeProperty prop) {
propsList.add(prop);
propNames.add(prop.getName());
}
public SqlTreeProperty[] getProps() {
return propsList.toArray(new SqlTreeProperty[propsList.size()]);
public STreeProperty[] getProps() {
return propsList.toArray(new STreeProperty[propsList.size()]);
}
boolean isPartialObject() {
@@ -97,7 +97,7 @@ public class SqlTreeProperties {
*/
private String aggregationJoin() {
if (!allProperties) {
for (SqlTreeProperty beanProperty : propsList) {
for (STreeProperty beanProperty : propsList) {
if (beanProperty.isAggregation()) {
aggregation = true;
aggregationPath = beanProperty.getElPrefix();