You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2010/01/23 09:04:08 UTC
svn commit: r902364 - in
/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src:
main/java/org/apache/cayenne/access/
main/java/org/apache/cayenne/access/jdbc/ main/java/org/apache/cayenne/ejbql/
main/java/org/apache/cayenne/ejbql/parser/ main/ja...
Author: aadamchik
Date: Sat Jan 23 08:04:01 2010
New Revision: 902364
URL: http://svn.apache.org/viewvc?rev=902364&view=rev
Log:
CAY-1366 EJBQL: Support for fetch joins
patch by Ksenia Khailenko
Added:
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/DataContextEJBQLFetchJoinTest.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/resources/dml/access.DataContextEJBQLFetchJoinTest.xml
Modified:
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataDomainQueryAction.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/HierarchicalObjectResolver.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/PrefetchProcessorTreeBuilder.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLFromTranslator.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLIdentifierColumnsTranslator.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLSelectColumnsTranslator.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLSelectTranslator.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EntityRowReader.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/EJBQLCompiledExpression.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/CompiledExpression.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/Compiler.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/EJBQLInnerFetchJoin.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/EJBQLOuterFetchJoin.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/DefaultEntityResultSegment.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/EntityResult.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/query/EJBQLQuery.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/query/EJBQLQueryMetadata.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/query/PrefetchTreeNode.java
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataDomainQueryAction.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataDomainQueryAction.java?rev=902364&r1=902363&r2=902364&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataDomainQueryAction.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataDomainQueryAction.java Sat Jan 23 08:04:01 2010
@@ -20,11 +20,15 @@
package org.apache.cayenne.access;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import org.apache.cayenne.CayenneException;
import org.apache.cayenne.CayenneRuntimeException;
@@ -636,15 +640,31 @@
rowsColumn.add((DataRow) rows.get(i)[position]);
}
List<Persistent> objects;
-
- // take a shortcut when no prefetches exist...
+ if (prefetchTree != null) {
+ PrefetchTreeNode prefetchTreeNode = null;
+ for (PrefetchTreeNode prefetch : prefetchTree.getChildren()) {
+ if (descriptor.getEntity().getName().equals(prefetch.getEntityName())) {
+ if (prefetchTreeNode == null) {
+ prefetchTreeNode = new PrefetchTreeNode();
+ }
+ PrefetchTreeNode addPath = prefetchTreeNode.addPath(prefetch
+ .getPath());
+ addPath.setSemantics(PrefetchTreeNode.JOINT_PREFETCH_SEMANTICS);
+ addPath.setPhantom(false);
+ }
+ }
+ prefetchTree = prefetchTreeNode;
+ }
if (prefetchTree == null) {
objects = new ObjectResolver(context, descriptor, metadata
.isRefreshingObjects())
.synchronizedObjectsFromDataRows(rowsColumn);
}
else {
- HierarchicalObjectResolver resolver = new HierarchicalObjectResolver(context, metadata);
+ HierarchicalObjectResolver resolver = new HierarchicalObjectResolver(
+ context,
+ metadata,
+ descriptor, true);
objects = resolver.synchronizedObjectsFromDataRows(
prefetchTree,
rowsColumn,
@@ -660,7 +680,6 @@
List<Object> rsMapping = metadata.getResultSetMapping();
int width = rsMapping.size();
-
// no conversions needed for scalar positions; reuse Object[]'s to fill them
// with resolved objects
List<List<?>> resultLists = new ArrayList<List<?>>(width);
@@ -670,16 +689,27 @@
EntityResultSegment entitySegment = (EntityResultSegment) rsMapping
.get(i);
List<Persistent> nextResult = toObjects(entitySegment
- .getClassDescriptor(), null, mainRows, i);
+ .getClassDescriptor(), metadata.getPrefetchTree() , mainRows, i);
+
resultLists.add(nextResult);
-
+
for (int j = 0; j < rowsLen; j++) {
Object[] row = mainRows.get(j);
row[i] = nextResult.get(j);
}
}
}
-
+ Set<List<?>> seen = new HashSet(mainRows.size());
+ Iterator<Object[]> it = mainRows.iterator();
+ while (it.hasNext()) {
+
+ if (!seen.add(Arrays.asList(it.next()))) {
+ it.remove();
+
+ }
+
+ }
+
// invoke callbacks now that all objects are resolved...
LifecycleCallbackRegistry callbackRegistry = context
.getEntityResolver()
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/HierarchicalObjectResolver.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/HierarchicalObjectResolver.java?rev=902364&r1=902363&r2=902364&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/HierarchicalObjectResolver.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/HierarchicalObjectResolver.java Sat Jan 23 08:04:01 2010
@@ -32,6 +32,7 @@
import org.apache.cayenne.query.PrefetchProcessor;
import org.apache.cayenne.query.PrefetchTreeNode;
import org.apache.cayenne.query.QueryMetadata;
+import org.apache.cayenne.reflect.ClassDescriptor;
/**
* Processes a number of DataRow sets corresponding to a given prefetch tree, resolving
@@ -43,6 +44,8 @@
DataContext context;
QueryMetadata queryMetadata;
DataRowStore cache;
+ ClassDescriptor descriptor;
+ boolean needToSaveDuplicates;
HierarchicalObjectResolver(DataContext context, QueryMetadata queryMetadata) {
this.queryMetadata = queryMetadata;
@@ -50,6 +53,13 @@
this.cache = context.getObjectStore().getDataRowCache();
}
+ HierarchicalObjectResolver(DataContext context, QueryMetadata metadata,
+ ClassDescriptor descriptor, boolean needToSaveDuplicates) {
+ this(context, metadata);
+ this.descriptor = descriptor;
+ this.needToSaveDuplicates = needToSaveDuplicates;
+ }
+
/**
* Properly synchronized version of 'resolveObjectTree'.
*/
@@ -175,7 +185,7 @@
// TODO: see TODO in ObjectResolver.relatedObjectsFromDataRows
- if (node.isDisjointPrefetch()) {
+ if (node.isDisjointPrefetch() && !needToSaveDuplicates) {
PrefetchProcessorNode processorNode = (PrefetchProcessorNode) node;
if (processorNode.isJointChildren()) {
List<Persistent> objects = processorNode.getObjects();
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/PrefetchProcessorTreeBuilder.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/PrefetchProcessorTreeBuilder.java?rev=902364&r1=902363&r2=902364&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/PrefetchProcessorTreeBuilder.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/PrefetchProcessorTreeBuilder.java Sat Jan 23 08:04:01 2010
@@ -36,6 +36,7 @@
private PrefetchProcessorNode root;
private LinkedList<PrefetchProcessorNode> nodeStack;
+ private ClassDescriptor descriptor;
private List mainResultRows;
private Map extraResultsByPath;
@@ -45,6 +46,7 @@
this.queryMetadata = objectTreeResolver.queryMetadata;
this.mainResultRows = mainResultRows;
this.extraResultsByPath = extraResultsByPath;
+ this.descriptor=objectTreeResolver.descriptor;
}
PrefetchProcessorNode buildTree(PrefetchTreeNode tree) {
@@ -147,7 +149,11 @@
}
else {
arc = null;
- descriptor = queryMetadata.getClassDescriptor();
+ if(this.descriptor!=null){
+ descriptor=this.descriptor;
+ }else{
+ descriptor = queryMetadata.getClassDescriptor();
+ }
rows = mainResultRows;
}
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLFromTranslator.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLFromTranslator.java?rev=902364&r1=902363&r2=902364&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLFromTranslator.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLFromTranslator.java Sat Jan 23 08:04:01 2010
@@ -21,7 +21,9 @@
import org.apache.cayenne.ejbql.EJBQLBaseVisitor;
import org.apache.cayenne.ejbql.EJBQLExpression;
import org.apache.cayenne.ejbql.parser.EJBQLFromItem;
+import org.apache.cayenne.ejbql.parser.EJBQLInnerFetchJoin;
import org.apache.cayenne.ejbql.parser.EJBQLJoin;
+import org.apache.cayenne.ejbql.parser.EJBQLOuterFetchJoin;
/**
* @since 3.0
@@ -66,8 +68,14 @@
@Override
public boolean visitInnerFetchJoin(EJBQLJoin join) {
- // TODO: andrus, 4/9/2007 - support for prefetching
- throw new UnsupportedOperationException("Fetch joins are not yet supported");
+ joinAppender.appendInnerJoin(
+ null,
+ new EJBQLTableId(join.getLeftHandSideId()),
+ new EJBQLTableId(((EJBQLInnerFetchJoin) join).getRightHandSideId()));
+
+ context.markCurrentPosition(EJBQLJoinAppender
+ .makeJoinTailMarker(((EJBQLInnerFetchJoin) join).getRightHandSideId()));
+ return false;
}
@Override
@@ -84,8 +92,14 @@
@Override
public boolean visitOuterFetchJoin(EJBQLJoin join) {
- // TODO: andrus, 4/9/2007 - support for prefetching
- throw new UnsupportedOperationException("Fetch joins are not yet supported");
+ joinAppender.appendOuterJoin(
+ null,
+ new EJBQLTableId(join.getLeftHandSideId()),
+ new EJBQLTableId(((EJBQLOuterFetchJoin) join).getRightHandSideId()));
+
+ context.markCurrentPosition(EJBQLJoinAppender
+ .makeJoinTailMarker(((EJBQLOuterFetchJoin) join).getRightHandSideId()));
+ return false;
}
@Override
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLIdentifierColumnsTranslator.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLIdentifierColumnsTranslator.java?rev=902364&r1=902363&r2=902364&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLIdentifierColumnsTranslator.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLIdentifierColumnsTranslator.java Sat Jan 23 08:04:01 2010
@@ -27,12 +27,16 @@
import org.apache.cayenne.dba.TypesMapping;
import org.apache.cayenne.ejbql.EJBQLBaseVisitor;
import org.apache.cayenne.ejbql.EJBQLExpression;
+import org.apache.cayenne.exp.Expression;
import org.apache.cayenne.map.DbAttribute;
import org.apache.cayenne.map.DbEntity;
import org.apache.cayenne.map.DbJoin;
import org.apache.cayenne.map.DbRelationship;
import org.apache.cayenne.map.ObjAttribute;
+import org.apache.cayenne.map.ObjEntity;
import org.apache.cayenne.map.ObjRelationship;
+import org.apache.cayenne.map.PathComponent;
+import org.apache.cayenne.query.PrefetchTreeNode;
import org.apache.cayenne.reflect.ArcProperty;
import org.apache.cayenne.reflect.AttributeProperty;
import org.apache.cayenne.reflect.ClassDescriptor;
@@ -151,9 +155,58 @@
appendColumn(idVar, attribute, attribute.getDbAttribute(), fields);
}
+ addPrefetchedColumnsIfAny(idVar);
+
return false;
}
+ private void addPrefetchedColumnsIfAny(final String visitedIdentifier) {
+ PrefetchTreeNode prefetchTree = context.getCompiledExpression().getPrefetchTree();
+ if (prefetchTree != null) {
+ for (PrefetchTreeNode prefetch : prefetchTree.adjacentJointNodes()) {
+ ClassDescriptor descriptor = context.getEntityDescriptor(prefetch
+ .getEjbqlPathEntityId());
+ if (visitedIdentifier.equals(prefetch.getEjbqlPathEntityId())) {
+ DbEntity table = descriptor.getRootDbEntities().iterator().next();
+ ObjEntity objectEntity = descriptor.getEntity();
+ prefetch.setEntityName(objectEntity.getName());
+ Expression prefetchExp = Expression.fromString(prefetch.getPath());
+ Expression dbPrefetch = objectEntity.translateToDbPath(prefetchExp);
+
+ DbRelationship r = null;
+ for (PathComponent<DbAttribute, DbRelationship> component : table
+ .resolvePath(dbPrefetch, context
+ .getMetadata()
+ .getPathSplitAliases())) {
+ r = component.getRelationship();
+
+ }
+
+ if (r == null) {
+ throw new CayenneRuntimeException("Invalid joint prefetch '"
+ + prefetch
+ + "' for entity: "
+ + objectEntity.getName());
+ }
+
+ Iterator<DbAttribute> targetAttributes = (Iterator<DbAttribute>) r
+ .getTargetEntity()
+ .getAttributes()
+ .iterator();
+ while (targetAttributes.hasNext()) {
+ DbAttribute attribute = targetAttributes.next();
+ appendColumn(prefetch.getEjbqlPathEntityId()
+ + "."
+ + prefetch.getPath(), attribute, "", prefetch.getPath()
+ + "."
+ + attribute.getName(), null);
+
+ }
+ }
+ }
+ }
+ }
+
public void appendColumn(
String identifier,
ObjAttribute property,
@@ -168,6 +221,20 @@
DbAttribute column,
Map<String, String> fields,
String javaType) {
+ String columnLabel = "";
+ if (context.isAppendingResultColumns()) {
+ columnLabel = fields.get(property != null ? property
+ .getDbAttributePath() : column.getName());
+ }
+ appendColumn(identifier, column, columnLabel, columnLabel, javaType);
+ }
+
+ public void appendColumn(
+ String identifier,
+ DbAttribute column,
+ String columnAlias,
+ String dataRowKey,
+ String javaType) {
DbEntity table = (DbEntity) column.getEntity();
String alias = context.getTableAlias(identifier, table.getFullyQualifiedName());
@@ -190,18 +257,15 @@
javaType = TypesMapping.getJavaBySqlType(column.getType());
}
- String columnLabel = fields.get(property != null ? property
- .getDbAttributePath() : column.getName());
-
// TODO: andrus 6/27/2007 - the last parameter is an unofficial "jdbcType"
// pending CAY-813 implementation, switch to #column directive
context
.append("' '")
.append(javaType)
.append("' '")
- .append(columnLabel)
+ .append(columnAlias)
.append("' '")
- .append(columnLabel)
+ .append(dataRowKey)
.append("' " + column.getType())
.append(")");
}
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLSelectColumnsTranslator.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLSelectColumnsTranslator.java?rev=902364&r1=902363&r2=902364&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLSelectColumnsTranslator.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLSelectColumnsTranslator.java Sat Jan 23 08:04:01 2010
@@ -104,26 +104,11 @@
context.append(!first ? ", " : " ");
DbAttribute dbAttribute = it.next();
-
- if (context.isAppendingResultColumns()) {
- context.append(" #result('");
- }
- else {
- context.append(' ');
- }
-
- context.append(alias).append('.').append(dbAttribute.getName());
-
- if (context.isAppendingResultColumns()) {
-
- String javaType = TypesMapping.getJavaBySqlType(dbAttribute
- .getType());
- String columnLabel = fields.get(dbAttribute.getName());
-
- context.append("' '").append(javaType).append("' '").append(
- columnLabel).append("' '").append(columnLabel).append(
- "' " + dbAttribute.getType()).append(")");
- }
+ appendColumn(
+ TypesMapping.getJavaBySqlType(dbAttribute.getType()),
+ alias,
+ dbAttribute,
+ fields!=null?fields.get(dbAttribute.getName()):"");
first = false;
}
@@ -151,11 +136,13 @@
else if (pathPart instanceof DbAttribute) {
DbAttribute dbAttribute = (DbAttribute) pathPart;
appendColumn(
- attribute,
+ attribute.getType(),
context.getTableAlias(
lhsId.getEntityId(),
dbAttribute.getEntity().getName()),
- dbAttribute);
+ dbAttribute,
+ context.isAppendingResultColumns() ? context
+ .nextColumnAlias() : "");
}
@@ -166,38 +153,8 @@
DbAttribute dbAttribute = attribute.getDbAttribute();
- appendColumn(attribute, alias, dbAttribute);
- }
- }
-
- private void appendColumn(
- ObjAttribute attribute,
- String alias,
- DbAttribute dbAttribute) {
- if (context.isAppendingResultColumns()) {
- context.append(" #result('");
- }
- else {
- context.append(' ');
- }
-
- context.append(alias).append('.').append(dbAttribute.getName());
-
- if (context.isAppendingResultColumns()) {
- String columnAlias = context.nextColumnAlias();
-
- // TODO: andrus 6/27/2007 - the last parameter is an unofficial
- // "jdbcType"
- // pending CAY-813 implementation, switch to #column directive
- context
- .append("' '")
- .append(attribute.getType())
- .append("' '")
- .append(columnAlias)
- .append("' '")
- .append(columnAlias)
- .append("' " + dbAttribute.getType())
- .append(")");
+ appendColumn(attribute.getType(), alias, dbAttribute, context
+ .isAppendingResultColumns() ? context.nextColumnAlias() : "");
}
}
@@ -213,4 +170,37 @@
return false;
}
+ public void appendColumn(
+ String javaType,
+ String alias,
+ DbAttribute dbAttribute,
+ String columnAlias) {
+ if (context.isAppendingResultColumns()) {
+ context.append(" #result('");
+ }
+ else {
+ context.append(' ');
+ }
+
+ context.append(alias).append('.').append(dbAttribute.getName());
+
+ if (context.isAppendingResultColumns()) {
+ // String columnAlias = context.nextColumnAlias();
+
+ // TODO: andrus 6/27/2007 - the last parameter is an unofficial
+ // "jdbcType"
+ // pending CAY-813 implementation, switch to #column directive
+ context
+ .append("' '")
+ .append(javaType)
+ .append("' '")
+ .append(columnAlias)
+ .append("' '")
+ .append(columnAlias)
+ .append("' " + dbAttribute.getType())
+ .append(")");
+ }
+
+ }
+
}
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLSelectTranslator.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLSelectTranslator.java?rev=902364&r1=902363&r2=902364&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLSelectTranslator.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLSelectTranslator.java Sat Jan 23 08:04:01 2010
@@ -116,4 +116,5 @@
expression.visit(context.getTranslatorFactory().getConditionTranslator(context));
return false;
}
+
}
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EntityRowReader.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EntityRowReader.java?rev=902364&r1=902363&r2=902364&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EntityRowReader.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EntityRowReader.java Sat Jan 23 08:04:01 2010
@@ -65,7 +65,12 @@
// query translator may change the order of fields compare to the entity
// result, so figure out DataRow labels by doing reverse lookup of
// RowDescriptor labels...
- labels[i] = segmentMetadata.getColumnPath(columns[startIndex + i].getDataRowKey());
+ if(columns[startIndex + i].getDataRowKey().contains(".")){
+ // if the dataRowKey contains ".", it is prefetched column and we can use it instead of search the name by alias
+ labels[i]=columns[startIndex + i].getDataRowKey();
+ }else{
+ labels[i] = segmentMetadata.getColumnPath(columns[startIndex + i].getDataRowKey());
+ }
}
}
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/EJBQLCompiledExpression.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/EJBQLCompiledExpression.java?rev=902364&r1=902363&r2=902364&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/EJBQLCompiledExpression.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/EJBQLCompiledExpression.java Sat Jan 23 08:04:01 2010
@@ -22,6 +22,7 @@
import org.apache.cayenne.map.DbRelationship;
import org.apache.cayenne.map.SQLResult;
+import org.apache.cayenne.query.PrefetchTreeNode;
import org.apache.cayenne.reflect.ClassDescriptor;
/**
@@ -63,4 +64,9 @@
* expression.
*/
SQLResult getResult();
+
+ /**
+ * Returns prefetched columns tree for fetch joins.
+ */
+ PrefetchTreeNode getPrefetchTree();
}
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/CompiledExpression.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/CompiledExpression.java?rev=902364&r1=902363&r2=902364&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/CompiledExpression.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/CompiledExpression.java Sat Jan 23 08:04:01 2010
@@ -27,6 +27,7 @@
import org.apache.cayenne.map.DbRelationship;
import org.apache.cayenne.map.ObjRelationship;
import org.apache.cayenne.map.SQLResult;
+import org.apache.cayenne.query.PrefetchTreeNode;
import org.apache.cayenne.reflect.ClassDescriptor;
/**
@@ -42,7 +43,9 @@
private Map<String, ObjRelationship> incomingById;
private EJBQLExpression expression;
private SQLResult result;
-
+ private PrefetchTreeNode prefetchTree;
+
+
public ClassDescriptor getEntityDescriptor(String idVariable) {
if (idVariable == null) {
return null;
@@ -99,4 +102,12 @@
void setResult(SQLResult resultSetMapping) {
this.result = resultSetMapping;
}
+
+ public PrefetchTreeNode getPrefetchTree() {
+ return prefetchTree;
+ }
+
+ public void setPrefetchTree(PrefetchTreeNode prefetchTree) {
+ this.prefetchTree = prefetchTree;
+ }
}
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/Compiler.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/Compiler.java?rev=902364&r1=902363&r2=902364&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/Compiler.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/Compiler.java Sat Jan 23 08:04:01 2010
@@ -40,6 +40,7 @@
import org.apache.cayenne.map.ObjAttribute;
import org.apache.cayenne.map.ObjRelationship;
import org.apache.cayenne.map.SQLResult;
+import org.apache.cayenne.query.PrefetchTreeNode;
import org.apache.cayenne.reflect.ArcProperty;
import org.apache.cayenne.reflect.AttributeProperty;
import org.apache.cayenne.reflect.ClassDescriptor;
@@ -69,7 +70,8 @@
private EJBQLExpressionVisitor pathVisitor;
private EJBQLExpressionVisitor rootDescriptorVisitor;
private List<Object> resultComponents;
-
+ private PrefetchTreeNode prefetchTree = null;
+
Compiler(EntityResolver resolver) {
this.resolver = resolver;
this.descriptorsById = new HashMap<String, ClassDescriptor>();
@@ -85,7 +87,7 @@
parsed.visit(new CompilationVisitor());
Map<EJBQLPath, Integer> pathsInSelect = new HashMap<EJBQLPath, Integer>();
-
+
if (parsed != null) {
for (int i = 0; i < parsed.getChildrenCount(); i++) {
if (parsed.getChild(i) instanceof EJBQLSelectClause) {
@@ -129,10 +131,8 @@
}
}
}
-
// postprocess paths, now that all id vars are resolved
if (paths != null) {
- int elenent = 0;
for (EJBQLPath path : paths) {
String id = normalizeIdPath(path.getId());
ClassDescriptor descriptor = descriptorsById.get(id);
@@ -156,7 +156,7 @@
incoming = ((ArcProperty) property).getRelationship();
descriptor = ((ArcProperty) property).getTargetDescriptor();
pathRelationshipString = buffer.substring(0, buffer.length());
-
+
descriptorsById.put(pathRelationshipString, descriptor);
incomingById.put(pathRelationshipString, incoming);
@@ -178,11 +178,12 @@
resultComponents.add(pathsInSelect.get(path).intValue(), ident);
rootId = pathRelationshipString;
}
- };
- elenent++;
+ }
}
}
-
+
+
+
CompiledExpression compiled = new CompiledExpression();
compiled.setExpression(parsed);
compiled.setSource(source);
@@ -190,7 +191,8 @@
compiled.setRootId(rootId);
compiled.setDescriptorsById(descriptorsById);
compiled.setIncomingById(incomingById);
-
+ compiled.setPrefetchTree(prefetchTree);
+
if (resultComponents != null) {
SQLResult mapping = new SQLResult();
@@ -200,9 +202,27 @@
mapping.addColumnResult((String) nextMapping);
}
else if (nextMapping instanceof EJBQLExpression) {
- mapping.addEntityResult(compileEntityResult(
+ EntityResult compileEntityResult = compileEntityResult(
(EJBQLExpression) nextMapping,
- i));
+ i);
+ if (prefetchTree != null) {
+ for (PrefetchTreeNode prefetch : prefetchTree.getChildren()) {
+ if (((EJBQLExpression) nextMapping).getText().equals(
+ prefetch.getEjbqlPathEntityId())) {
+ EJBQLIdentifier ident = new EJBQLIdentifier(0);
+ ident.text = prefetch.getEjbqlPathEntityId()
+ + "."
+ + prefetch.getPath();
+
+ compileEntityResult = compileEntityResultWithPrefetch(
+ compileEntityResult,
+ ident);
+
+ }
+ }
+ }
+ mapping.addEntityResult(compileEntityResult);
+
}
}
@@ -213,6 +233,72 @@
return compiled;
}
+ private EntityResult compileEntityResultWithPrefetch(EntityResult compiledResult, EJBQLExpression prefetchExpression){
+ final EntityResult result = compiledResult;
+ String id = prefetchExpression.getText().toLowerCase();
+ ClassDescriptor descriptor = descriptorsById.get(id);
+ if (descriptor == null) {
+ descriptor = descriptorsById.get(prefetchExpression.getText());
+ }
+ final String prefix = prefetchExpression.getText().substring(prefetchExpression.getText().indexOf(".")+1);
+
+ final Set<String> visited = new HashSet<String>();
+
+ PropertyVisitor visitor = new PropertyVisitor() {
+
+ public boolean visitAttribute(AttributeProperty property) {
+ ObjAttribute oa = property.getAttribute();
+ if (visited.add(oa.getDbAttributePath())) {
+ result.addObjectField(
+ oa.getEntity().getName(),
+ "fetch."+prefix+"."+oa.getName(),
+ prefix +"."+ oa.getDbAttributeName());
+ }
+ return true;
+ }
+
+ public boolean visitToMany(ToManyProperty property) {
+ return true;
+ }
+
+ public boolean visitToOne(ToOneProperty property) {
+ ObjRelationship rel = property.getRelationship();
+ DbRelationship dbRel = rel.getDbRelationships().get(0);
+
+ for (DbJoin join : dbRel.getJoins()) {
+ DbAttribute src = join.getSource();
+ if (src.isForeignKey() && visited.add(src.getName())) {
+ result.addDbField("fetch."+prefix+"."+src.getName(), prefix +"."+ src.getName());
+ }
+ }
+
+ return true;
+ }
+ };
+
+ descriptor.visitAllProperties(visitor);
+
+ // append id columns ... (some may have been appended already via relationships)
+ for (String pkName : descriptor.getEntity().getPrimaryKeyNames()) {
+ if (visited.add(pkName)) {
+ result.addDbField("fetch."+prefix+"."+pkName, prefix +"."+ pkName);
+ }
+ }
+
+ // append inheritance discriminator columns...
+ Iterator<ObjAttribute> discriminatorColumns = descriptor
+ .getDiscriminatorColumns();
+ while (discriminatorColumns.hasNext()) {
+ ObjAttribute column = discriminatorColumns.next();
+
+ if (visited.add(column.getName())) {
+ result.addDbField("fetch."+prefix+"."+column.getDbAttributePath(), prefix +"."+ column.getDbAttributePath());
+ }
+ }
+
+ return result;
+ }
+
private EntityResult compileEntityResult(EJBQLExpression expression, int position) {
String id = expression.getText().toLowerCase();
ClassDescriptor descriptor = descriptorsById.get(id);
@@ -329,6 +415,7 @@
@Override
public boolean visitInnerFetchJoin(EJBQLJoin join) {
+ prepareFetchJoin(join);
join.visit(joinVisitor);
return false;
}
@@ -341,6 +428,7 @@
@Override
public boolean visitOuterFetchJoin(EJBQLJoin join) {
+ prepareFetchJoin(join);
join.visit(joinVisitor);
return false;
}
@@ -370,6 +458,20 @@
public boolean visitSubselect(EJBQLExpression expression) {
return super.visitSubselect(expression);
}
+
+ private void prepareFetchJoin(EJBQLJoin join) {
+ if (prefetchTree == null) {
+ prefetchTree = new PrefetchTreeNode();
+ }
+ EJBQLPath fetchJoin = (EJBQLPath) join.getChild(0);
+ addPath(fetchJoin);
+
+ PrefetchTreeNode node = prefetchTree.addPath(fetchJoin.getRelativePath());
+ node.setSemantics(PrefetchTreeNode.JOINT_PREFETCH_SEMANTICS);
+ node.setPhantom(false);
+ node.setEjbqlPathEntityId(fetchJoin.getChild(0).getText());
+ }
+
}
class FromItemVisitor extends EJBQLBaseVisitor {
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/EJBQLInnerFetchJoin.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/EJBQLInnerFetchJoin.java?rev=902364&r1=902363&r2=902364&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/EJBQLInnerFetchJoin.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/EJBQLInnerFetchJoin.java Sat Jan 23 08:04:01 2010
@@ -33,4 +33,15 @@
protected boolean visitNode(EJBQLExpressionVisitor visitor) {
return visitor.visitInnerFetchJoin(this);
}
+
+ @Override
+ public String getRightHandSideId() {
+ int len = getChildrenCount();
+ if (len < 1) {
+ return null;
+ }
+
+ EJBQLPath path = (EJBQLPath) getChild(0);
+ return path.getAbsolutePath();
+ }
}
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/EJBQLOuterFetchJoin.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/EJBQLOuterFetchJoin.java?rev=902364&r1=902363&r2=902364&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/EJBQLOuterFetchJoin.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/EJBQLOuterFetchJoin.java Sat Jan 23 08:04:01 2010
@@ -33,4 +33,15 @@
protected boolean visitNode(EJBQLExpressionVisitor visitor) {
return visitor.visitOuterFetchJoin(this);
}
+
+ @Override
+ public String getRightHandSideId() {
+ int len = getChildrenCount();
+ if (len < 1) {
+ return null;
+ }
+
+ EJBQLPath path = (EJBQLPath) getChild(0);
+ return path.getAbsolutePath();
+ }
}
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/DefaultEntityResultSegment.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/DefaultEntityResultSegment.java?rev=902364&r1=902363&r2=902364&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/DefaultEntityResultSegment.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/DefaultEntityResultSegment.java Sat Jan 23 08:04:01 2010
@@ -18,6 +18,7 @@
****************************************************************/
package org.apache.cayenne.map;
+import java.util.HashMap;
import java.util.Map;
import org.apache.cayenne.query.EntityResultSegment;
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/EntityResult.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/EntityResult.java?rev=902364&r1=902363&r2=902364&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/EntityResult.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/EntityResult.java Sat Jan 23 08:04:01 2010
@@ -58,12 +58,11 @@
}
Map<String, String> dbFields = new HashMap<String, String>();
- for (FieldResult field : fields) {
- if (field.isDbAttribute()) {
+ for (FieldResult field : fields) {
+ if(field.isDbAttribute()||field.getAttributeName().startsWith("fetch.")){
dbFields.put(field.getAttributeName(), field.getColumn());
- }
- else {
+ } else {
ObjEntity entity = field.getEntityName() != null ? resolver
.getObjEntity(field.getEntityName()) : getRootEntity(resolver);
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/query/EJBQLQuery.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/query/EJBQLQuery.java?rev=902364&r1=902363&r2=902364&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/query/EJBQLQuery.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/query/EJBQLQuery.java Sat Jan 23 08:04:01 2010
@@ -125,7 +125,7 @@
throws EJBQLException {
if (expression == null) {
this.expression = EJBQLParserFactory.getParser().compile(
- ejbqlStatement,
+ ejbqlStatement,
resolver);
}
@@ -270,4 +270,6 @@
public int getStatementFetchSize() {
return metadata.getStatementFetchSize();
}
+
+
}
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/query/EJBQLQueryMetadata.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/query/EJBQLQueryMetadata.java?rev=902364&r1=902363&r2=902364&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/query/EJBQLQueryMetadata.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/query/EJBQLQueryMetadata.java Sat Jan 23 08:04:01 2010
@@ -36,7 +36,7 @@
boolean resolve(EntityResolver resolver, EJBQLQuery query) {
EJBQLCompiledExpression expression = query.getExpression(resolver);
-
+ setPrefetchTree(expression.getPrefetchTree());
resultSetMapping = expression.getResult() != null ? expression
.getResult()
.getResolvedComponents(resolver) : null;
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/query/PrefetchTreeNode.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/query/PrefetchTreeNode.java?rev=902364&r1=902363&r2=902364&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/query/PrefetchTreeNode.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/query/PrefetchTreeNode.java Sat Jan 23 08:04:01 2010
@@ -45,6 +45,8 @@
protected String name;
protected boolean phantom;
protected int semantics;
+ protected String ejbqlPathEntityId;
+ protected String entityName;
// transient parent allows cloning parts of the tree via serialization
protected transient PrefetchTreeNode parent;
@@ -343,6 +345,23 @@
public boolean isDisjointPrefetch() {
return semantics == DISJOINT_PREFETCH_SEMANTICS;
}
+
+ public String getEjbqlPathEntityId() {
+ return ejbqlPathEntityId;
+ }
+
+ public void setEjbqlPathEntityId(String ejbqlPathEntityId) {
+ this.ejbqlPathEntityId = ejbqlPathEntityId;
+ }
+
+ public String getEntityName() {
+ return entityName;
+ }
+
+ public void setEntityName(String entityName) {
+ this.entityName = entityName;
+ }
+
// **** custom serialization that supports serializing subtrees...
Added: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/DataContextEJBQLFetchJoinTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/DataContextEJBQLFetchJoinTest.java?rev=902364&view=auto
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/DataContextEJBQLFetchJoinTest.java (added)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/DataContextEJBQLFetchJoinTest.java Sat Jan 23 08:04:01 2010
@@ -0,0 +1,362 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.access;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.art.Artist;
+import org.apache.art.ArtistExhibit;
+import org.apache.art.Gallery;
+import org.apache.art.Painting;
+import org.apache.cayenne.PersistenceState;
+import org.apache.cayenne.ValueHolder;
+import org.apache.cayenne.query.EJBQLQuery;
+import org.apache.cayenne.unit.CayenneCase;
+
+public class DataContextEJBQLFetchJoinTest extends CayenneCase {
+
+ @Override
+ protected void setUp() throws Exception {
+ deleteTestData();
+ }
+
+ public void testFetchJoinForOneEntity() throws Exception {
+ createTestData("testOneEntityFetchJoin");
+ String ejbql = "SELECT a FROM Artist a JOIN FETCH a.paintingArray ";
+
+ EJBQLQuery query = new EJBQLQuery(ejbql);
+
+ DataContext context = createDataContext();
+
+ List objects = context.performQuery(query);
+
+ blockQueries();
+ try {
+ assertEquals(2, objects.size());
+
+ Iterator it = objects.iterator();
+ while (it.hasNext()) {
+ Artist a = (Artist) it.next();
+ List list = a.getPaintingArray();
+
+ assertNotNull(list);
+ assertFalse(((ValueHolder) list).isFault());
+
+ Iterator children = list.iterator();
+ while (children.hasNext()) {
+ Painting p = (Painting) children.next();
+ assertEquals(PersistenceState.COMMITTED, p.getPersistenceState());
+ // make sure properties are not null..
+ assertNotNull(p.getPaintingTitle());
+ }
+ }
+ }
+ finally {
+ unblockQueries();
+ }
+ }
+
+ public void testSeveralFetchJoins() throws Exception {
+ createTestData("testSeveralFetchJoins");
+ String ejbql = "SELECT a "
+ + "FROM Artist a JOIN FETCH a.paintingArray JOIN FETCH a.artistExhibitArray "
+ + "WHERE a.artistName = 'A1'";
+
+ EJBQLQuery query = new EJBQLQuery(ejbql);
+
+ DataContext context = createDataContext();
+
+ List objects = context.performQuery(query);
+
+ blockQueries();
+ try {
+ assertEquals(1, objects.size());
+
+ Artist a = (Artist) objects.get(0);
+ assertEquals("A1", a.getArtistName());
+
+ List<Painting> paintings = a.getPaintingArray();
+
+ assertNotNull(paintings);
+ assertFalse(((ValueHolder) paintings).isFault());
+ assertEquals(2, paintings.size());
+
+ List<String> expectedPaintingsNames = new ArrayList<String>();
+ expectedPaintingsNames.add("P11");
+ expectedPaintingsNames.add("P12");
+
+ Iterator<Painting> paintingsIterator = paintings.iterator();
+ while (paintingsIterator.hasNext()) {
+ Painting p = paintingsIterator.next();
+ assertEquals(PersistenceState.COMMITTED, p.getPersistenceState());
+ assertNotNull(p.getPaintingTitle());
+ assertTrue(expectedPaintingsNames.contains(p.getPaintingTitle()));
+ }
+
+ List<ArtistExhibit> exibits = a.getArtistExhibitArray();
+
+ assertNotNull(exibits);
+ assertFalse(((ValueHolder) exibits).isFault());
+ assertEquals(2, exibits.size());
+
+ Iterator<ArtistExhibit> exibitsIterator = exibits.iterator();
+ while (exibitsIterator.hasNext()) {
+ ArtistExhibit ae = exibitsIterator.next();
+ assertEquals(PersistenceState.COMMITTED, ae.getPersistenceState());
+ assertNotNull(ae.getObjectId());
+
+ }
+
+ }
+ finally {
+ unblockQueries();
+ }
+ }
+
+ public void testSeveralEntitiesFetchJoins() throws Exception {
+ createTestData("testSeveralFetchJoins");
+ String ejbql = "SELECT DISTINCT a , g "
+ + "FROM Artist a JOIN FETCH a.paintingArray , Gallery g JOIN FETCH g.exhibitArray "
+ + "WHERE a.artistName='A1' AND g.galleryName='gallery1'";
+
+ EJBQLQuery query = new EJBQLQuery(ejbql);
+
+ DataContext context = createDataContext();
+
+ List objects = context.performQuery(query);
+
+ blockQueries();
+ try {
+ assertNotNull(objects);
+ assertFalse(objects.isEmpty());
+ assertEquals(1, objects.size());
+ }
+ finally {
+ unblockQueries();
+ }
+ }
+
+ public void testSeveralEntitiesAndScalarFetchInnerJoins() throws Exception {
+ createTestData("testSeveralFetchJoins");
+ String ejbql = "SELECT DISTINCT a, a.artistName , g "
+ + "FROM Artist a JOIN FETCH a.paintingArray, Gallery g JOIN FETCH g.exhibitArray "
+ + "ORDER BY a.artistName";
+
+ EJBQLQuery query = new EJBQLQuery(ejbql);
+
+ DataContext context = createDataContext();
+
+ List objects = context.performQuery(query);
+
+ blockQueries();
+ try {
+ assertEquals(2, objects.size());
+
+ Object[] firstRow = (Object[]) objects.get(0);
+ Artist a = (Artist) firstRow[0];
+ assertEquals("A1", a.getArtistName());
+
+ List<Painting> paintings = a.getPaintingArray();
+
+ assertNotNull(paintings);
+ assertFalse(((ValueHolder) paintings).isFault());
+ assertEquals(2, paintings.size());
+
+ List<String> expectedPaintingsNames = new ArrayList<String>();
+ expectedPaintingsNames.add("P11");
+ expectedPaintingsNames.add("P12");
+
+ Iterator<Painting> paintingsIterator = paintings.iterator();
+ while (paintingsIterator.hasNext()) {
+ Painting p = paintingsIterator.next();
+ assertEquals(PersistenceState.COMMITTED, p.getPersistenceState());
+ assertNotNull(p.getPaintingTitle());
+ assertTrue(expectedPaintingsNames.contains(p.getPaintingTitle()));
+ }
+ String artistName = (String) firstRow[1];
+ assertEquals("A1", artistName);
+
+ Gallery g1 = (Gallery) firstRow[2];
+ assertEquals("gallery1", g1.getGalleryName());
+
+ List exibits = g1.getExhibitArray();
+
+ assertNotNull(exibits);
+ assertFalse(((ValueHolder) exibits).isFault());
+ assertEquals(2, exibits.size());
+
+ Object[] secondRow = (Object[]) objects.get(1);
+ a = (Artist) secondRow[0];
+ assertEquals("A2", a.getArtistName());
+
+ paintings = a.getPaintingArray();
+
+ assertNotNull(paintings);
+ assertFalse(((ValueHolder) paintings).isFault());
+ assertEquals(1, paintings.size());
+
+ expectedPaintingsNames = new ArrayList<String>();
+ expectedPaintingsNames.add("P2");
+
+ paintingsIterator = paintings.iterator();
+ while (paintingsIterator.hasNext()) {
+ Painting p = paintingsIterator.next();
+ assertEquals(PersistenceState.COMMITTED, p.getPersistenceState());
+ assertNotNull(p.getPaintingTitle());
+ assertTrue(expectedPaintingsNames.contains(p.getPaintingTitle()));
+ }
+ artistName = (String) secondRow[1];
+ assertEquals("A2", artistName);
+
+ Gallery g2 = (Gallery) secondRow[2];
+ assertEquals(g1, g2);
+ }
+ finally {
+ unblockQueries();
+ }
+ }
+
+ public void testSeveralEntitiesAndScalarFetchOuterJoins() throws Exception {
+ createTestData("testSeveralFetchJoins");
+ String ejbql = "SELECT DISTINCT a, a.artistName , g "
+ + "FROM Artist a LEFT JOIN FETCH a.paintingArray, Gallery g LEFT JOIN FETCH g.exhibitArray "
+ + "ORDER BY a.artistName";
+
+ EJBQLQuery query = new EJBQLQuery(ejbql);
+
+ DataContext context = createDataContext();
+
+ List objects = context.performQuery(query);
+
+ blockQueries();
+ try {
+ assertEquals(6, objects.size());
+
+ Object[] row = (Object[]) objects.get(0);
+ Artist a1 = (Artist) row[0];
+ assertEquals("A1", a1.getArtistName());
+
+ List<Painting> paintings = a1.getPaintingArray();
+
+ assertNotNull(paintings);
+ assertFalse(((ValueHolder) paintings).isFault());
+ assertEquals(2, paintings.size());
+
+ List<String> expectedPaintingsNames = new ArrayList<String>();
+ expectedPaintingsNames.add("P11");
+ expectedPaintingsNames.add("P12");
+
+ Iterator<Painting> paintingsIterator = paintings.iterator();
+ while (paintingsIterator.hasNext()) {
+ Painting p = paintingsIterator.next();
+ assertEquals(PersistenceState.COMMITTED, p.getPersistenceState());
+ assertNotNull(p.getPaintingTitle());
+ assertTrue(expectedPaintingsNames.contains(p.getPaintingTitle()));
+ }
+ String artistName1 = (String) row[1];
+ assertEquals("A1", artistName1);
+
+ Gallery g1 = (Gallery) row[2];
+ assertEquals("gallery1", g1.getGalleryName());
+
+ List exibits = g1.getExhibitArray();
+
+ assertNotNull(exibits);
+ assertFalse(((ValueHolder) exibits).isFault());
+ assertEquals(2, exibits.size());
+
+ row = (Object[]) objects.get(1);
+
+ assertEquals(a1, (Artist) row[0]);
+ assertEquals(artistName1, row[1]);
+
+ Gallery g2 = (Gallery) row[2];
+ assertEquals("gallery2", g2.getGalleryName());
+
+ exibits = g2.getExhibitArray();
+
+ assertTrue(exibits.isEmpty());
+
+ row = (Object[]) objects.get(2);
+
+ Artist a2 = (Artist) row[0];
+ assertEquals("A2", a2.getArtistName());
+
+ paintings = a2.getPaintingArray();
+
+ assertNotNull(paintings);
+ assertEquals(1, paintings.size());
+
+ Painting p = paintings.get(0);
+ assertEquals(PersistenceState.COMMITTED, p.getPersistenceState());
+ assertNotNull(p.getPaintingTitle());
+ assertEquals("P2", p.getPaintingTitle());
+
+ String artistName2 = (String) row[1];
+ assertEquals("A2", artistName2);
+ assertEquals(g2, row[2]);
+
+ row = (Object[]) objects.get(3);
+
+ assertEquals(a2, (Artist) row[0]);
+ assertEquals(artistName2, row[1]);
+ assertEquals(g1, row[2]);
+
+ row = (Object[]) objects.get(4);
+
+ Artist a3 = (Artist) row[0];
+ assertEquals("A3", a3.getArtistName());
+
+ paintings = a3.getPaintingArray();
+
+ assertTrue(paintings.isEmpty());
+
+ String artistName3 = (String) row[1];
+ assertEquals("A3", artistName3);
+ assertEquals(g1, row[2]);
+
+ row = (Object[]) objects.get(5);
+
+ assertEquals(a3, (Artist) row[0]);
+ assertEquals(artistName3, row[1]);
+ assertEquals(g2, row[2]);
+ }
+ finally {
+ unblockQueries();
+ }
+ }
+
+ public void testFlattenedFetchJoins() throws Exception {
+ createTestData("testSeveralFetchJoins");
+ String ejbql = "SELECT a "
+ + "FROM Artist a JOIN FETCH a.paintingArray.toPaintingInfo";
+
+ EJBQLQuery query = new EJBQLQuery(ejbql);
+
+ DataContext context = createDataContext();
+
+ // TODO fails because of error translating of chain join relationship
+ /*
+ * List objects = context.performQuery(query); blockQueries(); try { } finally {
+ * unblockQueries(); }
+ */
+ }
+}
Added: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/resources/dml/access.DataContextEJBQLFetchJoinTest.xml
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/resources/dml/access.DataContextEJBQLFetchJoinTest.xml?rev=902364&view=auto
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/resources/dml/access.DataContextEJBQLFetchJoinTest.xml (added)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/resources/dml/access.DataContextEJBQLFetchJoinTest.xml Sat Jan 23 08:04:01 2010
@@ -0,0 +1,178 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
+
+<beans default-lazy-init="true">
+ <bean id="A1" class="org.apache.cayenne.unit.util.UpdatingSQLTemplate">
+ <constructor-arg type="java.lang.Class">
+ <value>org.apache.art.Artist</value>
+ </constructor-arg>
+ <constructor-arg>
+ <value>insert into ARTIST (ARTIST_ID, ARTIST_NAME) values (1, 'A1')</value>
+ </constructor-arg>
+ </bean>
+
+ <bean id="A2" class="org.apache.cayenne.unit.util.UpdatingSQLTemplate">
+ <constructor-arg type="java.lang.Class">
+ <value>org.apache.art.Artist</value>
+ </constructor-arg>
+ <constructor-arg>
+ <value>insert into ARTIST (ARTIST_ID, ARTIST_NAME) values (2, 'A2')</value>
+ </constructor-arg>
+ </bean>
+
+ <bean id="A3" class="org.apache.cayenne.unit.util.UpdatingSQLTemplate">
+ <constructor-arg type="java.lang.Class">
+ <value>org.apache.art.Artist</value>
+ </constructor-arg>
+ <constructor-arg>
+ <value>insert into ARTIST (ARTIST_ID, ARTIST_NAME) values (3, 'A3')</value>
+ </constructor-arg>
+ </bean>
+
+ <bean id="P11" class="org.apache.cayenne.unit.util.UpdatingSQLTemplate">
+ <constructor-arg type="java.lang.Class">
+ <value>org.apache.art.Painting</value>
+ </constructor-arg>
+ <constructor-arg>
+ <value>
+ INSERT INTO PAINTING (PAINTING_ID, PAINTING_TITLE, ARTIST_ID, ESTIMATED_PRICE)
+ VALUES (1, 'P11', 1, 3000)
+ </value>
+ </constructor-arg>
+ </bean>
+
+ <bean id="P21" class="org.apache.cayenne.unit.util.UpdatingSQLTemplate">
+ <constructor-arg type="java.lang.Class">
+ <value>org.apache.art.Painting</value>
+ </constructor-arg>
+ <constructor-arg>
+ <value>
+ INSERT INTO PAINTING (PAINTING_ID, PAINTING_TITLE, ARTIST_ID, ESTIMATED_PRICE)
+ VALUES (2, 'P2', 2, 5000)
+ </value>
+ </constructor-arg>
+ </bean>
+
+ <bean id="P12" class="org.apache.cayenne.unit.util.UpdatingSQLTemplate">
+ <constructor-arg type="java.lang.Class">
+ <value>org.apache.art.Painting</value>
+ </constructor-arg>
+ <constructor-arg>
+ <value>
+ INSERT INTO PAINTING (PAINTING_ID, PAINTING_TITLE, ARTIST_ID, ESTIMATED_PRICE)
+ VALUES (3, 'P12', 1, 3000)
+ </value>
+ </constructor-arg>
+ </bean>
+
+ <bean id="P22" class="org.apache.cayenne.unit.util.UpdatingSQLTemplate">
+ <constructor-arg type="java.lang.Class">
+ <value>org.apache.art.Painting</value>
+ </constructor-arg>
+ <constructor-arg>
+ <value>
+ INSERT INTO PAINTING (PAINTING_ID, PAINTING_TITLE, ARTIST_ID, ESTIMATED_PRICE)
+ VALUES (4, 'P22', 2, 3000)
+ </value>
+ </constructor-arg>
+ </bean>
+
+ <bean id="P13" class="org.apache.cayenne.unit.util.UpdatingSQLTemplate">
+ <constructor-arg type="java.lang.Class">
+ <value>org.apache.art.Painting</value>
+ </constructor-arg>
+ <constructor-arg>
+ <value>
+ INSERT INTO PAINTING (PAINTING_ID, GALLERY_ID, PAINTING_TITLE, ARTIST_ID, ESTIMATED_PRICE)
+ VALUES (5, 1, 'C1', 1, 5000)
+ </value>
+ </constructor-arg>
+ </bean>
+
+ <bean id="P23" class="org.apache.cayenne.unit.util.UpdatingSQLTemplate">
+ <constructor-arg type="java.lang.Class">
+ <value>org.apache.art.Painting</value>
+ </constructor-arg>
+ <constructor-arg>
+ <value>
+ INSERT INTO PAINTING (PAINTING_ID, GALLERY_ID, PAINTING_TITLE, ARTIST_ID, ESTIMATED_PRICE)
+ VALUES (6, 2, 'C2', 2, 5000)
+ </value>
+ </constructor-arg>
+ </bean>
+
+ <bean id="G1" class="org.apache.cayenne.unit.util.UpdatingSQLTemplate">
+ <constructor-arg type="java.lang.Class"><value>org.apache.art.Gallery</value></constructor-arg>
+ <constructor-arg><value>
+ INSERT INTO GALLERY (GALLERY_ID, GALLERY_NAME) VALUES (1, 'gallery1')
+ </value></constructor-arg>
+ </bean>
+
+ <bean id="G2" class="org.apache.cayenne.unit.util.UpdatingSQLTemplate">
+ <constructor-arg type="java.lang.Class"><value>org.apache.art.Gallery</value></constructor-arg>
+ <constructor-arg><value>
+ INSERT INTO GALLERY (GALLERY_ID, GALLERY_NAME) VALUES (2, 'gallery2')
+ </value></constructor-arg>
+ </bean>
+
+ <bean id="E11" class="org.apache.cayenne.unit.util.UpdatingSQLTemplate">
+ <constructor-arg type="java.lang.Class"><value>org.apache.art.Exhibit</value></constructor-arg>
+ <constructor-arg><value>
+ INSERT INTO EXHIBIT (EXHIBIT_ID, GALLERY_ID, CLOSING_DATE, OPENING_DATE) VALUES (1, 1, '2009-10-01', '2009-10-02')
+ </value></constructor-arg>
+ </bean>
+ <bean id="E12" class="org.apache.cayenne.unit.util.UpdatingSQLTemplate">
+ <constructor-arg type="java.lang.Class"><value>org.apache.art.Exhibit</value></constructor-arg>
+ <constructor-arg><value>
+ INSERT INTO EXHIBIT (EXHIBIT_ID, GALLERY_ID, CLOSING_DATE, OPENING_DATE) VALUES (2, 1, '2009-10-01', '2009-10-02')
+ </value></constructor-arg>
+ </bean>
+ <bean id="AE11" class="org.apache.cayenne.unit.util.UpdatingSQLTemplate">
+ <constructor-arg type="java.lang.Class"><value>org.apache.art.ArtistExhibit</value></constructor-arg>
+ <constructor-arg><value>
+ INSERT INTO ARTIST_EXHIBIT (ARTIST_ID, EXHIBIT_ID) VALUES (1, 1)
+ </value></constructor-arg>
+ </bean>
+
+ <bean id="AE12" class="org.apache.cayenne.unit.util.UpdatingSQLTemplate">
+ <constructor-arg type="java.lang.Class"><value>org.apache.art.ArtistExhibit</value></constructor-arg>
+ <constructor-arg><value>
+ INSERT INTO ARTIST_EXHIBIT (ARTIST_ID, EXHIBIT_ID) VALUES (1, 2)
+ </value></constructor-arg>
+ </bean>
+ <!-- ======================================= -->
+ <!-- Data Sets -->
+ <!-- ======================================= -->
+
+ <bean id="testOneEntityFetchJoin" class="java.util.ArrayList">
+ <constructor-arg>
+ <list>
+ <ref bean="A1" />
+ <ref bean="A2" />
+ <ref bean="A3" />
+ <ref bean="P11" />
+ <ref bean="P12" />
+ <ref bean="P21" />
+ </list>
+ </constructor-arg>
+ </bean>
+ <bean id="testSeveralFetchJoins" class="java.util.ArrayList">
+ <constructor-arg>
+ <list>
+ <ref bean="A1" />
+ <ref bean="A2" />
+ <ref bean="A3" />
+ <ref bean="P11" />
+ <ref bean="P12" />
+ <ref bean="P21" />
+ <ref bean="G1" />
+ <ref bean="G2" />
+ <ref bean="E11" />
+ <ref bean="E12" />
+ <ref bean="AE11" />
+ <ref bean="AE12" />
+ </list>
+ </constructor-arg>
+ </bean>
+
+</beans>
\ No newline at end of file