Fix for #112 - ENH (411) : RawSql to support discriminator column mapping.

This commit is contained in:
Rob Bygrave
2014-05-17 00:11:44 +12:00
parent 41f3173adf
commit 8c8442ec58
11 changed files with 460 additions and 381 deletions
@@ -257,21 +257,21 @@ public class CQueryBuilder implements Constants {
ElPropertyValue el = descriptor.getElGetValue(propertyName);
if (el == null) {
String msg = "Property [" + propertyName + "] not found on " + descriptor.getFullName();
throw new PersistenceException(msg);
}
BeanProperty beanProperty = el.getBeanProperty();
if (beanProperty.isId()) {
// For @Id properties we chop off the last part of the path
propertyName = SplitName.parent(propertyName);
} else if (beanProperty instanceof BeanPropertyAssocOne<?>) {
String msg = "Column [" + column.getDbColumn() + "] mapped to complex Property[" + propertyName + "]";
msg += ". It should be mapped to a simple property (proably the Id property). ";
throw new PersistenceException(msg);
}
if (propertyName != null) {
String[] pathProp = SplitName.split(propertyName);
pathProps.addToPath(pathProp[0], pathProp[1]);
throw new PersistenceException("Property [" + propertyName + "] not found on " + descriptor.getFullName());
} else {
BeanProperty beanProperty = el.getBeanProperty();
if (beanProperty.isId() || beanProperty.isDiscriminator()) {
// For @Id properties we chop off the last part of the path
propertyName = SplitName.parent(propertyName);
} else if (beanProperty instanceof BeanPropertyAssocOne<?>) {
String msg = "Column [" + column.getDbColumn() + "] mapped to complex Property[" + propertyName + "]";
msg += ". It should be mapped to a simple property (proably the Id property). ";
throw new PersistenceException(msg);
}
if (propertyName != null) {
String[] pathProp = SplitName.split(propertyName);
pathProps.addToPath(pathProp[0], pathProp[1]);
}
}
}
}
@@ -6,39 +6,49 @@ import java.util.List;
import com.avaje.ebean.RawSql.ColumnMapping;
import com.avaje.ebean.config.dbplatform.SqlLimitResponse;
import com.avaje.ebeaninternal.server.core.OrmQueryRequest;
import com.avaje.ebeaninternal.server.deploy.InheritInfo;
import com.avaje.ebeaninternal.server.type.DataReader;
import com.avaje.ebeaninternal.server.type.RsetDataReaderIndexed;
/**
* RawSql based query plan.
*/
public class CQueryPlanRawSql extends CQueryPlan {
private final int[] rsetIndexPositions;
public CQueryPlanRawSql(OrmQueryRequest<?> request, SqlLimitResponse sqlRes, SqlTree sqlTree, String logWhereSql) {
super(request, sqlRes, sqlTree, true, logWhereSql);
this.rsetIndexPositions = createIndexPositions(request, sqlTree);
private final int[] rsetIndexPositions;
public CQueryPlanRawSql(OrmQueryRequest<?> request, SqlLimitResponse sqlRes, SqlTree sqlTree, String logWhereSql) {
super(request, sqlRes, sqlTree, true, logWhereSql);
this.rsetIndexPositions = createIndexPositions(request, sqlTree);
}
public DataReader createDataReader(ResultSet rset) {
return new RsetDataReaderIndexed(rset, rsetIndexPositions, isRowNumberIncluded());
}
private int[] createIndexPositions(OrmQueryRequest<?> request, SqlTree sqlTree) {
List<String> chain = sqlTree.buildSelectExpressionChain();
ColumnMapping columnMapping = request.getQuery().getRawSql().getColumnMapping();
InheritInfo inheritInfo = request.getBeanDescriptor().getInheritInfo();
boolean addDiscriminator = inheritInfo != null;
int offset = addDiscriminator ? 1 : 0;
int[] indexPositions = new int[chain.size() + offset];
if (addDiscriminator) {
// discriminator column must always be first in the query
indexPositions[0] = 1;
}
for (int i = 0; i < chain.size(); i++) {
String expr = chain.get(i);
int indexPos = 1 + columnMapping.getIndexPosition(expr);
indexPositions[i + offset] = indexPos;
}
public DataReader createDataReader(ResultSet rset){
return new RsetDataReaderIndexed(rset, rsetIndexPositions, isRowNumberIncluded());
}
private int[] createIndexPositions(OrmQueryRequest<?> request, SqlTree sqlTree) {
List<String> chain = sqlTree.buildSelectExpressionChain();
ColumnMapping columnMapping = request.getQuery().getRawSql().getColumnMapping();
int[] indexPositions = new int[chain.size()];
for (int i = 0; i < chain.size(); i++) {
String expr = chain.get(i);
int indexPos = 1 + columnMapping.getIndexPosition(expr);
indexPositions[i] = indexPos;
}
return indexPositions;
}
return indexPositions;
}
}
@@ -69,8 +69,7 @@ public class SqlTreeBuilder {
/**
* Construct for RawSql query.
*/
public SqlTreeBuilder(OrmQueryRequest<?> request, CQueryPredicates predicates,
OrmQueryDetail queryDetail) {
public SqlTreeBuilder(OrmQueryRequest<?> request, CQueryPredicates predicates, OrmQueryDetail queryDetail) {
this.rawSql = true;
this.desc = request.getBeanDescriptor();
@@ -240,9 +239,7 @@ public class SqlTreeBuilder {
Set<String> includes = manyWhereJoins.getJoins();
for (String joinProp : includes) {
BeanPropertyAssoc<?> beanProperty = (BeanPropertyAssoc<?>) desc
.getBeanPropertyFromPath(joinProp);
BeanPropertyAssoc<?> beanProperty = (BeanPropertyAssoc<?>) desc.getBeanPropertyFromPath(joinProp);
SqlTreeNodeManyWhereJoin nodeJoin = new SqlTreeNodeManyWhereJoin(joinProp, beanProperty);
myJoinList.add(nodeJoin);
}
@@ -334,8 +331,7 @@ public class SqlTreeBuilder {
BeanProperty p = desc.findBeanProperty(propName);
if (p == null) {
logger
.error("property [" + propName + "]not found on " + desc + " for query - excluding it.");
logger.error("property [" + propName + "]not found on " + desc + " for query - excluding it.");
} else if (p instanceof BeanPropertyAssoc<?> && p.isEmbedded()) {
// if the property is embedded we need to lookup the real column name
@@ -368,9 +364,7 @@ public class SqlTreeBuilder {
if (!selectProps.containsProperty(baseName)) {
BeanProperty p = desc.findBeanProperty(baseName);
if (p == null) {
String m = "property [" + propName + "] not found on " + desc
+ " for query - excluding it.";
logger.error(m);
logger.error("property [" + propName + "] not found on " + desc + " for query - excluding it.");
} else if (p.isEmbedded()) {
// add the embedded bean (and effectively
@@ -378,8 +372,7 @@ public class SqlTreeBuilder {
selectProps.add(p);
} else {
String m = "property [" + p.getFullBeanName()
+ "] expected to be an embedded bean for query - excluding it.";
String m = "property [" + p.getFullBeanName() + "] expected to be an embedded bean for query - excluding it.";
logger.error(m);
}
}
@@ -389,8 +382,9 @@ public class SqlTreeBuilder {
// sub class hierarchy if required
BeanProperty p = desc.findBeanProperty(propName);
if (p == null) {
logger.error("property [" + propName + "] not found on " + desc
+ " for query - excluding it.");
logger.error("property [" + propName + "] not found on " + desc + " for query - excluding it.");
p = desc.findBeanProperty("id");
selectProps.add(p);
} else if (p.isId()) {
// do not bother to include id for normal queries as the
@@ -415,7 +409,7 @@ public class SqlTreeBuilder {
private SqlTreeProperties getBaseSelectPartial(BeanDescriptor<?> desc, OrmQueryProperties queryProps) {
SqlTreeProperties selectProps = new SqlTreeProperties(desc);
SqlTreeProperties selectProps = new SqlTreeProperties();
selectProps.setReadOnly(queryProps.isReadOnly());
// add properties in the order in which they appear
@@ -443,7 +437,7 @@ public class SqlTreeBuilder {
return getBaseSelectPartial(desc, queryProps);
}
SqlTreeProperties selectProps = new SqlTreeProperties(desc);
SqlTreeProperties selectProps = new SqlTreeProperties();
selectProps.setAllProperties(true);
// normal simple properties of the bean
@@ -486,9 +480,7 @@ public class SqlTreeBuilder {
if (manyProperty != null) {
// only one many associated allowed to be included in fetch
if (logger.isDebugEnabled()) {
String msg = "Not joining [" + propName + "] as already joined to a Many[" + manyProperty
+ "].";
logger.debug(msg);
logger.debug("Not joining [" + propName + "] as already joined to a Many[" + manyProperty + "].");
}
return false;
}
@@ -3,9 +3,7 @@ package com.avaje.ebeaninternal.server.query;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.deploy.TableJoin;
@@ -15,44 +13,35 @@ import com.avaje.ebeaninternal.server.deploy.TableJoin;
public class SqlTreeProperties {
private static final TableJoin[] EMPTY_TABLE_JOINS = new TableJoin[0];
private final BeanDescriptor<?> desc;
// /**
// * The included Properties that will be used by EntityBeanIntercept
// * to determine lazy loading on partial objects.
// */
Set<String> includedProps;
/**
* True if this node of the tree should have read only entity beans.
*/
boolean readOnly;
private boolean readOnly;
/**
* set to false if the id field is not included.
*/
boolean includeId = true;
private boolean includeId = true;
TableJoin[] tableJoins = EMPTY_TABLE_JOINS;
private TableJoin[] tableJoins = EMPTY_TABLE_JOINS;
/**
* The bean properties in order.
*/
List<BeanProperty> propsList = new ArrayList<BeanProperty>();
private List<BeanProperty> propsList = new ArrayList<BeanProperty>();
/**
* Maintain a list of property names to detect embedded bean additions.
*/
LinkedHashSet<String> propNames = new LinkedHashSet<String>();
private LinkedHashSet<String> propNames = new LinkedHashSet<String>();
private boolean allProperties;
public SqlTreeProperties(BeanDescriptor<?> desc) {
this.desc = desc;
public SqlTreeProperties() {
}
public boolean containsProperty(String propName){
public boolean containsProperty(String propName){
return propNames.contains(propName);
}