mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
#115 - Mapping - Add support for @ElementCollection enhancement
Initial support - simple List.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
+12
-2
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user