createEmptyNoParent() {
+ return null;
+ }
+
+ /**
+ * Do nothing for this case.
+ */
+ @Override
+ public void add(BeanCollection> collection, EntityBean bean, boolean withCheck) {
+ // do nothing
+ }
+}
diff --git a/src/main/java/io/ebeaninternal/server/query/CQueryPlan.java b/src/main/java/io/ebeaninternal/server/query/CQueryPlan.java
index a9f7921cd..a0d9a46b1 100644
--- a/src/main/java/io/ebeaninternal/server/query/CQueryPlan.java
+++ b/src/main/java/io/ebeaninternal/server/query/CQueryPlan.java
@@ -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;
diff --git a/src/main/java/io/ebeaninternal/server/query/CQueryPredicates.java b/src/main/java/io/ebeaninternal/server/query/CQueryPredicates.java
index 98fe40941..5df1633c0 100644
--- a/src/main/java/io/ebeaninternal/server/query/CQueryPredicates.java
+++ b/src/main/java/io/ebeaninternal/server/query/CQueryPredicates.java
@@ -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();
diff --git a/src/main/java/io/ebeaninternal/server/query/ExtraJoin.java b/src/main/java/io/ebeaninternal/server/query/ExtraJoin.java
new file mode 100644
index 000000000..c246c651d
--- /dev/null
+++ b/src/main/java/io/ebeaninternal/server/query/ExtraJoin.java
@@ -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;
+ }
+}
diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeProperty.java b/src/main/java/io/ebeaninternal/server/query/STreeProperty.java
similarity index 85%
rename from src/main/java/io/ebeaninternal/server/query/SqlTreeProperty.java
rename to src/main/java/io/ebeaninternal/server/query/STreeProperty.java
index 2543cc825..340766e9a 100644
--- a/src/main/java/io/ebeaninternal/server/query/SqlTreeProperty.java
+++ b/src/main/java/io/ebeaninternal/server/query/STreeProperty.java
@@ -8,10 +8,10 @@ import java.util.List;
/**
* A property in the SQL Tree.
- *
+ *
* 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).
*/
diff --git a/src/main/java/io/ebeaninternal/server/query/STreePropertyAssoc.java b/src/main/java/io/ebeaninternal/server/query/STreePropertyAssoc.java
new file mode 100644
index 000000000..1213d0b55
--- /dev/null
+++ b/src/main/java/io/ebeaninternal/server/query/STreePropertyAssoc.java
@@ -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);
+
+}
diff --git a/src/main/java/io/ebeaninternal/server/query/STreePropertyAssocMany.java b/src/main/java/io/ebeaninternal/server/query/STreePropertyAssocMany.java
new file mode 100644
index 000000000..9b6791e2f
--- /dev/null
+++ b/src/main/java/io/ebeaninternal/server/query/STreePropertyAssocMany.java
@@ -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();
+
+}
diff --git a/src/main/java/io/ebeaninternal/server/query/STreePropertyAssocOne.java b/src/main/java/io/ebeaninternal/server/query/STreePropertyAssocOne.java
new file mode 100644
index 000000000..722a43a02
--- /dev/null
+++ b/src/main/java/io/ebeaninternal/server/query/STreePropertyAssocOne.java
@@ -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();
+}
diff --git a/src/main/java/io/ebeaninternal/server/query/STreeType.java b/src/main/java/io/ebeaninternal/server/query/STreeType.java
new file mode 100644
index 000000000..e824272c0
--- /dev/null
+++ b/src/main/java/io/ebeaninternal/server/query/STreeType.java
@@ -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);
+
+
+}
diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTree.java b/src/main/java/io/ebeaninternal/server/query/SqlTree.java
index 8e7d1a2ee..d4207a9e8 100644
--- a/src/main/java/io/ebeaninternal/server/query/SqlTree.java
+++ b/src/main/java/io/ebeaninternal/server/query/SqlTree.java
@@ -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 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 includes, boolean includeJoins) {
+ STreeProperty[] encryptedProps, STreePropertyAssocMany manyProperty, Set 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;
}
diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeAlias.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeAlias.java
index 5e8319a1e..ea583c833 100644
--- a/src/main/java/io/ebeaninternal/server/query/SqlTreeAlias.java
+++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeAlias.java
@@ -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 propJoins, BeanDescriptor> desc) {
+ public void addJoin(Set 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);
}
diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java
index 8811096eb..9cfaad7e8 100644
--- a/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java
+++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java
@@ -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 joinList) {
+ private SqlTreeNode buildSelectChain(String prefix, STreePropertyAssoc prop,
+ STreeType desc, List joinList) {
List 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 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 myList, SqlTreeProperties props) {
+ private SqlTreeNode buildNode(String prefix, STreePropertyAssoc prop, STreeType desc, List 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 myList) {
+ private void buildExtraJoins(STreeType desc, List myList) {
if (rawSql) {
return;
@@ -383,25 +375,25 @@ public final class SqlTreeBuilder {
* This means it can included individual properties of an embedded bean.
*
*/
- 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 rootRegister = new HashMap<>();
- private final BeanDescriptor> desc;
+ private final STreeType desc;
- private IncludesDistiller(BeanDescriptor> desc, Set selectIncludes,
+ private IncludesDistiller(STreeType desc, Set selectIncludes,
Set 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.
*
*/
- 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)
diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java
index 806e64adb..96fd09d05 100644
--- a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java
+++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java
@@ -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 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 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 myList, boolean withId,
- BeanPropertyAssocMany> many, SpiQuery.TemporalMode temporalMode, boolean disableLazyLoad) {
+ SqlTreeNodeBean(STreeType desc, SqlTreeProperties props, List 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 myChildren, boolean withId, BeanPropertyAssocMany> lazyLoadParent,
+ private SqlTreeNodeBean(String prefix, STreePropertyAssoc beanProp, STreeType desc, SqlTreeProperties props,
+ List 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 createPathMap(String prefix, BeanDescriptor> desc) {
-
- BeanPropertyAssocMany>[] manys = desc.propertiesMany();
+ private Map createPathMap(String prefix, STreeType desc) {
HashMap 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);
diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeExtraJoin.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeExtraJoin.java
index ba83d4ced..17943ddd1 100644
--- a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeExtraJoin.java
+++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeExtraJoin.java
@@ -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 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 Version loadVersion(DbReadContext ctx) throws SQLException {
+ public Version loadVersion(DbReadContext ctx) {
return null;
}
diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyRoot.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyRoot.java
index 835d201b3..edeff9fce 100644
--- a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyRoot.java
+++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyRoot.java
@@ -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 myList,
+ SqlTreeNodeManyRoot(String prefix, STreePropertyAssocMany prop, SqlTreeProperties props, List myList,
SpiQuery.TemporalMode temporalMode, boolean disableLazyLoad) {
super(prefix, prop, props, myList, true, temporalMode, disableLazyLoad);
this.manyProp = prop;
diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyWhereJoin.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyWhereJoin.java
index 07ab86398..ae0a810ab 100644
--- a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyWhereJoin.java
+++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyWhereJoin.java
@@ -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 Version loadVersion(DbReadContext ctx) throws SQLException {
+ public Version loadVersion(DbReadContext ctx) {
// nothing to do here
return null;
}
diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeRoot.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeRoot.java
index bb93b25e1..74be7c415 100644
--- a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeRoot.java
+++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeRoot.java
@@ -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 myList, boolean withId,
- TableJoin includeJoin, BeanPropertyAssocMany> many, SpiQuery.TemporalMode temporalMode, boolean disableLazyLoad) {
+ SqlTreeNodeRoot(STreeType desc, SqlTreeProperties props, List myList, boolean withId,
+ TableJoin includeJoin, STreePropertyAssocMany many, SpiQuery.TemporalMode temporalMode, boolean disableLazyLoad) {
super(desc, props, myList, withId, many, temporalMode, disableLazyLoad);
this.includeJoin = includeJoin;
diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeProperties.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeProperties.java
index 9c717173e..5ec9b286d 100644
--- a/src/main/java/io/ebeaninternal/server/query/SqlTreeProperties.java
+++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeProperties.java
@@ -20,7 +20,7 @@ public class SqlTreeProperties {
/**
* The bean properties in order.
*/
- private final List propsList = new ArrayList<>();
+ private final List 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();
diff --git a/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryDetail.java b/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryDetail.java
index 6bdc89fd2..e7fa731b3 100644
--- a/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryDetail.java
+++ b/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryDetail.java
@@ -1,11 +1,11 @@
package io.ebeaninternal.server.querydefn;
import io.ebean.FetchConfig;
+import io.ebean.util.SplitName;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.BeanPropertyAssoc;
import io.ebeaninternal.server.el.ElPropertyDeploy;
import io.ebeaninternal.server.el.ElPropertyValue;
-import io.ebean.util.SplitName;
import javax.persistence.PersistenceException;
import java.io.Serializable;
@@ -427,7 +427,7 @@ public class OrmQueryDetail implements Serializable {
for (OrmQueryProperties joinProps : fetchPaths.values()) {
if (!joinProps.hasSelectClause()) {
BeanDescriptor> assocDesc = desc.getBeanDescriptor(joinProps.getPath());
- if (assocDesc.hasDefaultSelectClause()) {
+ if (assocDesc != null && assocDesc.hasDefaultSelectClause()) {
fetch(joinProps.getPath(), assocDesc.getDefaultSelectClause(), joinProps.getFetchConfig());
}
}
diff --git a/src/main/java/io/ebeanservice/docstore/api/support/DocStructure.java b/src/main/java/io/ebeanservice/docstore/api/support/DocStructure.java
index cad53baf2..e67e473f3 100644
--- a/src/main/java/io/ebeanservice/docstore/api/support/DocStructure.java
+++ b/src/main/java/io/ebeanservice/docstore/api/support/DocStructure.java
@@ -72,7 +72,7 @@ public class DocStructure {
public void prepareMany(BeanDescriptor desc) {
Set strings = embedded.keySet();
for (String prop : strings) {
- BeanPropertyAssoc> embProp = (BeanPropertyAssoc>) desc.findBeanProperty(prop);
+ BeanPropertyAssoc> embProp = (BeanPropertyAssoc>) desc.findProperty(prop);
if (embProp.isMany()) {
prepare(prop, embProp);
}
diff --git a/src/test/java/io/ebeaninternal/server/deploy/FormulaPropertyPathTest.java b/src/test/java/io/ebeaninternal/server/deploy/FormulaPropertyPathTest.java
index 9526619c9..d20581c0b 100644
--- a/src/test/java/io/ebeaninternal/server/deploy/FormulaPropertyPathTest.java
+++ b/src/test/java/io/ebeaninternal/server/deploy/FormulaPropertyPathTest.java
@@ -1,7 +1,7 @@
package io.ebeaninternal.server.deploy;
import io.ebean.BaseTestCase;
-import io.ebeaninternal.server.query.SqlTreeProperty;
+import io.ebeaninternal.server.query.STreeProperty;
import org.junit.Test;
import org.tests.model.basic.Customer;
@@ -76,7 +76,7 @@ public class FormulaPropertyPathTest extends BaseTestCase {
assertThat(propertyPath.alias()).isNull();
}
- SqlTreeProperty treeProperty = propertyPath.build();
+ STreeProperty treeProperty = propertyPath.build();
assertThat(treeProperty).isNotNull();
}
diff --git a/src/test/java/org/tests/basic/TestAnnotationBase.java b/src/test/java/org/tests/basic/TestAnnotationBase.java
index e40c36cd9..f84ec99ab 100644
--- a/src/test/java/org/tests/basic/TestAnnotationBase.java
+++ b/src/test/java/org/tests/basic/TestAnnotationBase.java
@@ -1,13 +1,13 @@
package org.tests.basic;
import io.ebean.BaseTestCase;
+import io.ebean.annotation.Platform;
import io.ebean.annotation.Where;
import io.ebean.util.AnnotationUtil;
-import io.ebean.annotation.Platform;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.BeanProperty;
-import org.tests.model.basic.ValidationGroupSomething;
import org.junit.Test;
+import org.tests.model.basic.ValidationGroupSomething;
import javax.persistence.Entity;
import javax.validation.constraints.NotNull;
@@ -125,23 +125,23 @@ public class TestAnnotationBase extends BaseTestCase {
@Test
- public void testFindMaxSize() throws NoSuchFieldException, SecurityException {
+ public void testFindMaxSize() throws SecurityException {
BeanDescriptor descriptor = spiEbeanServer().getBeanDescriptor(TestAnnotationBaseEntity.class);
- BeanProperty bp = descriptor.findBeanProperty("constraintAnnotation");
+ BeanProperty bp = descriptor.findProperty("constraintAnnotation");
assertEquals(40, bp.getDbLength());
}
@Test
- public void testNotNullWithGroup() throws NoSuchFieldException, SecurityException {
+ public void testNotNullWithGroup() throws SecurityException {
BeanDescriptor descriptor = spiEbeanServer().getBeanDescriptor(TestAnnotationBaseEntity.class);
- BeanProperty bp = descriptor.findBeanProperty("null1");
+ BeanProperty bp = descriptor.findProperty("null1");
assertFalse(bp.isNullable());
- bp = descriptor.findBeanProperty("null2");
+ bp = descriptor.findProperty("null2");
assertTrue(bp.isNullable());
- bp = descriptor.findBeanProperty("null3");
+ bp = descriptor.findProperty("null3");
assertTrue(bp.isNullable());
}
diff --git a/src/test/java/org/tests/model/elementcollection/EcPerson.java b/src/test/java/org/tests/model/elementcollection/EcPerson.java
new file mode 100644
index 000000000..00550b5c6
--- /dev/null
+++ b/src/test/java/org/tests/model/elementcollection/EcPerson.java
@@ -0,0 +1,69 @@
+package org.tests.model.elementcollection;
+
+import javax.persistence.CollectionTable;
+import javax.persistence.Column;
+import javax.persistence.ElementCollection;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.Version;
+import java.util.ArrayList;
+import java.util.List;
+
+@Entity
+public class EcPerson {
+
+ @Id
+ long id;
+
+ String name;
+
+ @ElementCollection
+ @CollectionTable(name = "ec_person_phone", joinColumns = @JoinColumn(name = "owner_id", referencedColumnName = "id"))
+ @Column(name = "phone")
+ List phoneNumbers = new ArrayList<>();
+
+ @Version
+ long version;
+
+ public EcPerson(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String toString() {
+ return "person id:" + id + " name:" + name + " phs:" + phoneNumbers;
+ }
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public List getPhoneNumbers() {
+ return phoneNumbers;
+ }
+
+ public void setPhoneNumbers(List phoneNumbers) {
+ this.phoneNumbers = phoneNumbers;
+ }
+
+ public long getVersion() {
+ return version;
+ }
+
+ public void setVersion(long version) {
+ this.version = version;
+ }
+}
diff --git a/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasic.java b/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasic.java
new file mode 100644
index 000000000..dd5ea2bc3
--- /dev/null
+++ b/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasic.java
@@ -0,0 +1,51 @@
+package org.tests.model.elementcollection;
+
+import io.ebean.BaseTestCase;
+import io.ebean.Ebean;
+import org.junit.Test;
+
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class TestElementCollectionBasic extends BaseTestCase {
+
+ @Test
+ public void test() {
+
+ EcPerson person = new EcPerson("Fiona021");
+ person.getPhoneNumbers().add("021 1234");
+ person.getPhoneNumbers().add("021 4321");
+ Ebean.save(person);
+
+
+ EcPerson person1 = new EcPerson("Fiona09");
+ person1.getPhoneNumbers().add("09 1234");
+ person1.getPhoneNumbers().add("09 4321");
+ Ebean.save(person1);
+
+ List found =
+ Ebean.find(EcPerson.class).where()
+ .startsWith("name", "Fiona0")
+ .order().asc("id")
+ .findList();
+
+ List phoneNumbers0 = found.get(0).getPhoneNumbers();
+ List phoneNumbers1 = found.get(1).getPhoneNumbers();
+ phoneNumbers0.size();
+
+ assertThat(phoneNumbers0).containsExactly("021 1234", "021 4321");
+ assertThat(phoneNumbers1).containsExactly("09 1234", "09 4321");
+
+
+ List found2 =
+ Ebean.find(EcPerson.class)
+ .fetch("phoneNumbers")
+ .where()
+ .startsWith("name", "Fiona0")
+ .order().asc("id")
+ .findList();
+
+ System.out.println(found2);
+ }
+}