diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanProperty.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanProperty.java index 5216f67ce..97af4fcfa 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanProperty.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanProperty.java @@ -73,6 +73,11 @@ public class BeanProperty implements ElPropertyValue { */ final boolean unidirectionalShadow; + /** + * Flag set if this maps to the inheritance discriminator column + */ + final boolean discriminator; + /** * Flag to mark the property as embedded. This could be on * BeanPropertyAssocOne rather than here. Put it here for checking Id type @@ -267,6 +272,7 @@ public class BeanProperty implements ElPropertyValue { this.propertyIndex = deploy.getPropertyIndex(); this.unidirectionalShadow = deploy.isUndirectionalShadow(); + this.discriminator = deploy.isDiscriminator(); this.localEncrypted = deploy.isLocalEncrypted(); this.dbEncrypted = deploy.isDbEncrypted(); this.dbEncryptedType = deploy.getDbEncryptedType(); @@ -305,12 +311,6 @@ public class BeanProperty implements ElPropertyValue { this.readMethod = deploy.getReadMethod(); this.writeMethod = deploy.getWriteMethod(); this.getter = deploy.getGetter(); - if (descriptor != null && getter == null) { - if (!unidirectionalShadow) { - String m = "Null Getter for: " + getFullBeanName(); - throw new RuntimeException(m); - } - } this.setter = deploy.getSetter(); this.dbColumn = tableAliasIntern(descriptor, deploy.getDbColumn(), false, null); @@ -368,6 +368,7 @@ public class BeanProperty implements ElPropertyValue { this.fetchEager = source.fetchEager; this.unidirectionalShadow = source.unidirectionalShadow; + this.discriminator = source.discriminator; this.localEncrypted = source.isLocalEncrypted(); this.isTransient = source.isTransient(); this.secondaryTable = source.isSecondaryTable(); @@ -469,6 +470,13 @@ public class BeanProperty implements ElPropertyValue { return formula; } + /** + * Return true if this property maps to the inheritance discriminator column. + */ + public boolean isDiscriminator() { + return discriminator; + } + public void copyProperty(EntityBean sourceBean, EntityBean destBean) { Object value = getValue(sourceBean); setValue(destBean, value); diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/DRawSqlSelect.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/DRawSqlSelect.java index 0a2321063..8d81e7680 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/DRawSqlSelect.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/DRawSqlSelect.java @@ -127,7 +127,7 @@ public class DRawSqlSelect { sqlTree.setSummary(desc.getName()); LinkedHashSet includedProps = new LinkedHashSet(); - SqlTreeProperties selectProps = new SqlTreeProperties(desc); + SqlTreeProperties selectProps = new SqlTreeProperties(); for (int i = 0; i < selectColumns.length; i++) { diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/InheritInfo.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/InheritInfo.java index 765f08aac..c2e429403 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/InheritInfo.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/InheritInfo.java @@ -13,338 +13,332 @@ import com.avaje.ebeaninternal.server.deploy.parse.DeployInheritInfo; import com.avaje.ebeaninternal.server.query.SqlTreeProperties; /** - * Represents a node in the Inheritance tree. Holds information regarding Super - * Subclass support. + * Represents a node in the Inheritance tree. Holds information regarding Super Subclass support. */ public class InheritInfo { - private final String discriminatorStringValue; - private final Object discriminatorValue; + private final String discriminatorStringValue; + private final Object discriminatorValue; - private final String discriminatorColumn; + private final String discriminatorColumn; - private final int discriminatorType; + private final int discriminatorType; - private final int discriminatorLength; + private final int discriminatorLength; - private final String where; + private final String where; - private final Class type; + private final Class type; - private final ArrayList children = new ArrayList(); + private final ArrayList children = new ArrayList(); - /** - * Map of discriminator values to InheritInfo. - */ - private final HashMap discMap; - - /** - * Map of class types to InheritInfo (taking into account subclass proxy classes). - */ - private final HashMap typeMap; + /** + * Map of discriminator values to InheritInfo. + */ + private final HashMap discMap; - private final InheritInfo parent; + /** + * Map of class types to InheritInfo (taking into account subclass proxy classes). + */ + private final HashMap typeMap; - private final InheritInfo root; + private final InheritInfo parent; - private BeanDescriptor descriptor; + private final InheritInfo root; - public InheritInfo(InheritInfo r, InheritInfo parent, DeployInheritInfo deploy) { - - this.parent = parent; - this.type = deploy.getType(); - this.discriminatorColumn = InternString.intern(deploy.getDiscriminatorColumn(parent)); - this.discriminatorValue = deploy.getDiscriminatorObjectValue(); - this.discriminatorStringValue = deploy.getDiscriminatorStringValue(); - - this.discriminatorType = deploy.getDiscriminatorType(parent); - this.discriminatorLength = deploy.getDiscriminatorLength(parent); - this.where = InternString.intern(deploy.getWhere()); - - if (r == null) { - // this is a root node - root = this; - discMap = new HashMap(); - typeMap = new HashMap(); - registerWithRoot(this); + private BeanDescriptor descriptor; - } else { - this.root = r; - // register with the root node... - discMap = null; - typeMap = null; - root.registerWithRoot(this); - } - } - - /** - * Visit all the children in the inheritance tree. - */ - public void visitChildren(InheritInfoVisitor visitor) { - - for (int i = 0; i < children.size(); i++) { - InheritInfo child = children.get(i); - visitor.visit(child); - child.visitChildren(visitor); - } - } + public InheritInfo(InheritInfo r, InheritInfo parent, DeployInheritInfo deploy) { - /** - * return true if anything in the inheritance hierarchy has a relationship - * with a save cascade on it. - */ - public boolean isSaveRecurseSkippable() { - return root.isNodeSaveRecurseSkippable(); - } - - private boolean isNodeSaveRecurseSkippable() { - if (!descriptor.isSaveRecurseSkippable()){ - return false; - } - for (int i = 0; i < children.size(); i++) { - InheritInfo child = children.get(i); - if (!child.isNodeSaveRecurseSkippable()){ - return false; - } - } - return true; - } - - /** - * return true if anything in the inheritance hierarchy has a relationship - * with a delete cascade on it. - */ - public boolean isDeleteRecurseSkippable() { - return root.isNodeDeleteRecurseSkippable(); + this.parent = parent; + this.type = deploy.getType(); + this.discriminatorColumn = InternString.intern(deploy.getDiscriminatorColumn(parent)); + this.discriminatorValue = deploy.getDiscriminatorObjectValue(); + this.discriminatorStringValue = deploy.getDiscriminatorStringValue(); + + this.discriminatorType = deploy.getDiscriminatorType(parent); + this.discriminatorLength = deploy.getDiscriminatorLength(parent); + this.where = InternString.intern(deploy.getWhere()); + + if (r == null) { + // this is a root node + root = this; + discMap = new HashMap(); + typeMap = new HashMap(); + registerWithRoot(this); + + } else { + this.root = r; + // register with the root node... + discMap = null; + typeMap = null; + root.registerWithRoot(this); + } + } + + /** + * Visit all the children in the inheritance tree. + */ + public void visitChildren(InheritInfoVisitor visitor) { + + for (int i = 0; i < children.size(); i++) { + InheritInfo child = children.get(i); + visitor.visit(child); + child.visitChildren(visitor); + } + } + + /** + * return true if anything in the inheritance hierarchy has a relationship with a save cascade on + * it. + */ + public boolean isSaveRecurseSkippable() { + return root.isNodeSaveRecurseSkippable(); + } + + private boolean isNodeSaveRecurseSkippable() { + if (!descriptor.isSaveRecurseSkippable()) { + return false; + } + for (int i = 0; i < children.size(); i++) { + InheritInfo child = children.get(i); + if (!child.isNodeSaveRecurseSkippable()) { + return false; + } + } + return true; + } + + /** + * return true if anything in the inheritance hierarchy has a relationship with a delete cascade + * on it. + */ + public boolean isDeleteRecurseSkippable() { + return root.isNodeDeleteRecurseSkippable(); + } + + private boolean isNodeDeleteRecurseSkippable() { + if (!descriptor.isDeleteRecurseSkippable()) { + return false; + } + for (int i = 0; i < children.size(); i++) { + InheritInfo child = children.get(i); + if (!child.isNodeDeleteRecurseSkippable()) { + return false; + } + } + return true; + } + + /** + * Set the descriptor for this node. + */ + public void setDescriptor(BeanDescriptor descriptor) { + + this.descriptor = descriptor; + } + + /** + * Return the associated BeanDescriptor for this node. + */ + public BeanDescriptor getBeanDescriptor() { + return descriptor; + } + + /** + * Get the bean property additionally looking in the sub types. + */ + public BeanProperty findSubTypeProperty(String propertyName) { + + BeanProperty prop = null; + + for (int i = 0, x = children.size(); i < x; i++) { + InheritInfo childInfo = children.get(i); + + // recursively search this child bean descriptor + prop = childInfo.getBeanDescriptor().findBeanProperty(propertyName); + + if (prop != null) { + return prop; + } } - private boolean isNodeDeleteRecurseSkippable() { - if (!descriptor.isDeleteRecurseSkippable()) { - return false; - } - for (int i = 0; i < children.size(); i++) { - InheritInfo child = children.get(i); - if (!child.isNodeDeleteRecurseSkippable()) { - return false; - } - } - return true; + return null; + } + + /** + * Add the local properties for each sub class below this one. + */ + public void addChildrenProperties(SqlTreeProperties selectProps) { + + for (int i = 0, x = children.size(); i < x; i++) { + InheritInfo childInfo = children.get(i); + selectProps.add(childInfo.descriptor.propertiesLocal()); + + childInfo.addChildrenProperties(selectProps); } - - /** - * Set the descriptor for this node. - */ - public void setDescriptor(BeanDescriptor descriptor) { - - this.descriptor = descriptor; - } - - /** - * Return the associated BeanDescriptor for this node. - */ - public BeanDescriptor getBeanDescriptor() { - return descriptor; - } - - /** - * Get the bean property additionally looking in the sub types. - */ - public BeanProperty findSubTypeProperty(String propertyName) { - - BeanProperty prop = null; - - for (int i = 0, x=children.size(); i < x; i++) { - InheritInfo childInfo = children.get(i); - - // recursively search this child bean descriptor - prop = childInfo.getBeanDescriptor().findBeanProperty(propertyName); - - if (prop != null){ - return prop; - } - } - - return null; - } - - /** - * Add the local properties for each sub class below this one. - */ - public void addChildrenProperties(SqlTreeProperties selectProps) { - - for (int i = 0, x=children.size(); i < x; i++) { - InheritInfo childInfo = children.get(i); - selectProps.add(childInfo.descriptor.propertiesLocal()); - - childInfo.addChildrenProperties(selectProps); - } - } + } - /** - * Return the associated InheritInfo for this DB row read. - */ - public InheritInfo readType(DbReadContext ctx) throws SQLException { + /** + * Return the associated InheritInfo for this DB row read. + */ + public InheritInfo readType(DbReadContext ctx) throws SQLException { - String discValue = ctx.getDataReader().getString(); - return readType(discValue); - } - - /** - * Return the associated InheritInfo for this discriminator value. - */ - public InheritInfo readType(String discValue) { + String discValue = ctx.getDataReader().getString(); + return readType(discValue); + } - if (discValue == null) { - return null; - } + /** + * Return the associated InheritInfo for this discriminator value. + */ + public InheritInfo readType(String discValue) { - InheritInfo typeInfo = root.getType(discValue); - if (typeInfo == null) { - String m = "Inheritance type for discriminator value [" + discValue + "] was not found?"; - throw new PersistenceException(m); - } - - return typeInfo; + if (discValue == null) { + return null; } - /** - * Return the associated InheritInfo for this bean type. - */ - public InheritInfo readType(Class beanType) { - - InheritInfo typeInfo = root.getTypeByClass(beanType); - if (typeInfo == null) { - String m = "Inheritance type for bean type [" + beanType.getName() + "] was not found?"; - throw new PersistenceException(m); - } - - return typeInfo; + InheritInfo typeInfo = root.getType(discValue); + if (typeInfo == null) { + throw new PersistenceException("Inheritance type for discriminator value [" + discValue + "] was not found?"); } + return typeInfo; + } - /** - * Create an EntityBean for this type. - */ - public EntityBean createEntityBean() { - return descriptor.createEntityBean(); - } - - /** - * Return the IdBinder for this type. - */ - public IdBinder getIdBinder() { - return descriptor.getIdBinder(); - } - - /** - * return the type. - */ - public Class getType() { - return type; - } + /** + * Return the associated InheritInfo for this bean type. + */ + public InheritInfo readType(Class beanType) { - /** - * Return the root node of the tree. - *

- * The root has a map of discriminator values to types. - *

- */ - public InheritInfo getRoot() { - return root; - } - - /** - * Return the parent node. - */ - public InheritInfo getParent() { - return parent; + InheritInfo typeInfo = root.getTypeByClass(beanType); + if (typeInfo == null) { + throw new PersistenceException("Inheritance type for bean type [" + beanType.getName() + "] was not found?"); } - - /** - * Return true if this is abstract node. - */ - public boolean isAbstract() { - return (discriminatorValue == null); - } + return typeInfo; + } - /** - * Return true if this is the root node. - */ - public boolean isRoot() { - return parent == null; - } + /** + * Create an EntityBean for this type. + */ + public EntityBean createEntityBean() { + return descriptor.createEntityBean(); + } - /** - * For a discriminator get the inheritance information for this tree. - */ - public InheritInfo getType(String discValue) { - return discMap.get(discValue); - } - - /** - * Return the InheritInfo for the given bean type. - */ - private InheritInfo getTypeByClass(Class beanType) { - return typeMap.get(beanType.getName()); + /** + * Return the IdBinder for this type. + */ + public IdBinder getIdBinder() { + return descriptor.getIdBinder(); + } + + /** + * return the type. + */ + public Class getType() { + return type; + } + + /** + * Return the root node of the tree. + *

+ * The root has a map of discriminator values to types. + *

+ */ + public InheritInfo getRoot() { + return root; + } + + /** + * Return the parent node. + */ + public InheritInfo getParent() { + return parent; + } + + /** + * Return true if this is abstract node. + */ + public boolean isAbstract() { + return (discriminatorValue == null); + } + + /** + * Return true if this is the root node. + */ + public boolean isRoot() { + return parent == null; + } + + /** + * For a discriminator get the inheritance information for this tree. + */ + public InheritInfo getType(String discValue) { + return discMap.get(discValue); + } + + /** + * Return the InheritInfo for the given bean type. + */ + private InheritInfo getTypeByClass(Class beanType) { + return typeMap.get(beanType.getName()); + } + + private void registerWithRoot(InheritInfo info) { + if (info.getDiscriminatorStringValue() != null) { + String stringDiscValue = info.getDiscriminatorStringValue(); + discMap.put(stringDiscValue, info); } + typeMap.put(info.getType().getName(), info); + } - private void registerWithRoot(InheritInfo info) { - if (info.getDiscriminatorStringValue() != null) { - String stringDiscValue = info.getDiscriminatorStringValue(); - discMap.put(stringDiscValue, info); - } - typeMap.put(info.getType().getName(), info); - } + /** + * Add a child node. + */ + public void addChild(InheritInfo childInfo) { + children.add(childInfo); + } - /** - * Add a child node. - */ - public void addChild(InheritInfo childInfo) { - children.add(childInfo); - } + /** + * Return the derived where for the discriminator. + */ + public String getWhere() { - /** - * Return the derived where for the discriminator. - */ - public String getWhere() { + return where; + } - return where; - } + /** + * Return the column name of the discriminator. + */ + public String getDiscriminatorColumn() { + return discriminatorColumn; + } - /** - * Return the column name of the discriminator. - */ - public String getDiscriminatorColumn() { - return discriminatorColumn; - } + /** + * Return the sql type of the discriminator value. + */ + public int getDiscriminatorType() { + return discriminatorType; + } - /** - * Return the sql type of the discriminator value. - */ - public int getDiscriminatorType() { - return discriminatorType; - } - - - /** - * Return the length of the discriminator column. - */ - public int getDiscriminatorLength() { - return discriminatorLength; - } + /** + * Return the length of the discriminator column. + */ + public int getDiscriminatorLength() { + return discriminatorLength; + } - /** - * Return the discriminator value for this node. - */ - public String getDiscriminatorStringValue() { - return discriminatorStringValue; - } + /** + * Return the discriminator value for this node. + */ + public String getDiscriminatorStringValue() { + return discriminatorStringValue; + } - public Object getDiscriminatorValue() { - return discriminatorValue; - } - - public String toString() { - return "InheritInfo[" + type.getName() + "] disc[" + discriminatorStringValue + "]"; - } + public Object getDiscriminatorValue() { + return discriminatorValue; + } + + public String toString() { + return "InheritInfo[" + type.getName() + "] disc[" + discriminatorStringValue + "]"; + } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanProperty.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanProperty.java index 33b9b9be2..a7eb6ba77 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanProperty.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanProperty.java @@ -86,6 +86,8 @@ public class DeployBeanProperty { private boolean unique; + private boolean discriminator; + /** * The length or precision of the DB column. */ @@ -336,6 +338,20 @@ public class DeployBeanProperty { this.undirectionalShadow = undirectionalShadow; } + /** + * Mark this property as mapping to the discriminator column. + */ + public void setDiscriminator(boolean discriminator) { + this.discriminator = discriminator; + } + + /** + * Return true if this property maps to the inheritance discriminator column.s + */ + public boolean isDiscriminator() { + return discriminator; + } + /** * Return true if the property is encrypted in java rather than in the DB. */ diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanPropertyLists.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanPropertyLists.java index 49a816638..6c21ce909 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanPropertyLists.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanPropertyLists.java @@ -16,7 +16,9 @@ import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany; import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne; import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompound; import com.avaje.ebeaninternal.server.deploy.BeanPropertySimpleCollection; +import com.avaje.ebeaninternal.server.deploy.InheritInfo; import com.avaje.ebeaninternal.server.deploy.TableJoin; +import com.avaje.ebeaninternal.server.type.ScalarTypeString; /** * Helper object to classify BeanProperties into appropriate lists. @@ -88,6 +90,21 @@ public class DeployBeanPropertyLists { allocateToList(prop); } + InheritInfo inheritInfo = deploy.getInheritInfo(); + if (inheritInfo != null) { + // Create a BeanProperty for the discriminator column to support + // using RawSql queries with inheritance + String discriminatorColumn = inheritInfo.getDiscriminatorColumn(); + DeployBeanProperty discDeployProp = new DeployBeanProperty(deploy, String.class, new ScalarTypeString(), null); + discDeployProp.setDiscriminator(true); + discDeployProp.setName(discriminatorColumn); + discDeployProp.setDbColumn(discriminatorColumn); + + // create the discriminator BeanProperty and only register it in the propertyMap + BeanProperty dprop = new BeanProperty(owner, desc, discDeployProp); + propertyMap.put(dprop.getName(), dprop); + } + List deployTableJoins = deploy.getTableJoins(); tableJoins = new TableJoin[deployTableJoins.size()]; for (int i = 0; i < deployTableJoins.size(); i++) { diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/parse/DeployInherit.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/parse/DeployInherit.java index ec0d5411e..84c8067de 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/parse/DeployInherit.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/parse/DeployInherit.java @@ -135,7 +135,8 @@ public class DeployInherit { } DiscriminatorColumn da = (DiscriminatorColumn) cls.getAnnotation(DiscriminatorColumn.class); if (da != null) { - info.setDiscriminatorColumn(da.name()); + // lowercase the discriminator column for RawSql and JSON + info.setDiscriminatorColumn(da.name().toLowerCase()); DiscriminatorType discriminatorType = da.discriminatorType(); if (discriminatorType.equals(DiscriminatorType.INTEGER)){ info.setDiscriminatorType(Types.INTEGER); diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryBuilder.java b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryBuilder.java index 06f3f0718..71f57db2a 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryBuilder.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryBuilder.java @@ -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]); + } } } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryPlanRawSql.java b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryPlanRawSql.java index 4fcc496df..d4db15cfc 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryPlanRawSql.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryPlanRawSql.java @@ -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 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 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; + } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeBuilder.java b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeBuilder.java index 107a59871..10372060e 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeBuilder.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeBuilder.java @@ -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 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; } diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeProperties.java b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeProperties.java index b93b5279d..9065d9b80 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeProperties.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeProperties.java @@ -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 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 propsList = new ArrayList(); + private List propsList = new ArrayList(); /** * Maintain a list of property names to detect embedded bean additions. */ - LinkedHashSet propNames = new LinkedHashSet(); + private LinkedHashSet propNames = new LinkedHashSet(); 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); } diff --git a/src/test/java/com/avaje/tests/inheritance/TestInheritanceRawSql.java b/src/test/java/com/avaje/tests/inheritance/TestInheritanceRawSql.java new file mode 100644 index 000000000..7ced4d957 --- /dev/null +++ b/src/test/java/com/avaje/tests/inheritance/TestInheritanceRawSql.java @@ -0,0 +1,52 @@ +package com.avaje.tests.inheritance; + +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; + +import com.avaje.ebean.BaseTestCase; +import com.avaje.ebean.Ebean; +import com.avaje.ebean.RawSql; +import com.avaje.ebean.RawSqlBuilder; +import com.avaje.tests.model.basic.Truck; +import com.avaje.tests.model.basic.Vehicle; + +public class TestInheritanceRawSql extends BaseTestCase { + + @Test + public void test() { + + Truck truck = new Truck(); + truck.setCapacity(50D); + truck.setLicenseNumber("ASB23"); + + Ebean.save(truck); + + + String sql = "select dtype, id, license_number from vehicle where id = :id"; + RawSqlBuilder rawSqlBuilder = RawSqlBuilder.parse(sql); + + RawSql rawSql = rawSqlBuilder.create(); + + List list = Ebean.find(Vehicle.class) + .setRawSql(rawSql) + .setParameter("id", truck.getId()) + .findList(); + + Assert.assertEquals(1, list.size()); + + Vehicle vehicle2 = list.get(0); + Assert.assertTrue(vehicle2 instanceof Truck); + + Truck truck2 = (Truck)vehicle2; + Assert.assertEquals("ASB23", truck2.getLicenseNumber()); + + // invoke lazy loading and set the capacity + truck2.setCapacity(30D); + + // and now save + Ebean.save(truck2); + } + +}