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/07/09 21:58:13 UTC
svn commit: r962674 - in /cayenne/main/branches/STABLE-3.0:
docs/doc/src/main/resources/
framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/
framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/remote/
framewo...
Author: aadamchik
Date: Fri Jul 9 19:58:13 2010
New Revision: 962674
URL: http://svn.apache.org/viewvc?rev=962674&view=rev
Log:
CAY-1452 EJBQL query scalar result is not supported
patch by Xenia Khailenko with some minor changes from me
Modified:
cayenne/main/branches/STABLE-3.0/docs/doc/src/main/resources/RELEASE-NOTES.txt
cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/ClientServerChannelQueryAction.java
cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/remote/ClientChannel.java
cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/CayenneContextEJBQLTest.java
Modified: cayenne/main/branches/STABLE-3.0/docs/doc/src/main/resources/RELEASE-NOTES.txt
URL: http://svn.apache.org/viewvc/cayenne/main/branches/STABLE-3.0/docs/doc/src/main/resources/RELEASE-NOTES.txt?rev=962674&r1=962673&r2=962674&view=diff
==============================================================================
--- cayenne/main/branches/STABLE-3.0/docs/doc/src/main/resources/RELEASE-NOTES.txt (original)
+++ cayenne/main/branches/STABLE-3.0/docs/doc/src/main/resources/RELEASE-NOTES.txt Fri Jul 9 19:58:13 2010
@@ -19,6 +19,7 @@ CAY-1380 Support for Escaped LIKE Clause
CAY-1402 Ability to use Terminating "@size" in Nested Properties Against Collections
CAY-1416 ExpressionFactory.noMatchExp.toEJBQL() produces incorrect output
CAY-1417 EJBQL doesn't support null numeric parameters
+CAY-1452 EJBQL query scalar result is not supported
CAY-1455 "NULL" JDBC type is shown for DbAttribute data types in the Modeler
CAY-1458 Document Vertical Inheritance
Modified: cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/ClientServerChannelQueryAction.java
URL: http://svn.apache.org/viewvc/cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/ClientServerChannelQueryAction.java?rev=962674&r1=962673&r2=962674&view=diff
==============================================================================
--- cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/ClientServerChannelQueryAction.java (original)
+++ cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/ClientServerChannelQueryAction.java Fri Jul 9 19:58:13 2010
@@ -20,7 +20,6 @@
package org.apache.cayenne.access;
import java.util.ArrayList;
-import java.util.Iterator;
import java.util.List;
import org.apache.cayenne.CayenneRuntimeException;
@@ -28,6 +27,7 @@ import org.apache.cayenne.ObjectId;
import org.apache.cayenne.Persistent;
import org.apache.cayenne.QueryResponse;
import org.apache.cayenne.map.EntityResolver;
+import org.apache.cayenne.query.EntityResultSegment;
import org.apache.cayenne.query.PrefetchTreeNode;
import org.apache.cayenne.query.Query;
import org.apache.cayenne.query.QueryMetadata;
@@ -173,37 +173,105 @@ class ClientServerChannelQueryAction {
private List toClientObjects(List serverObjects) {
- // create a list copy even if it is empty to ensure that we have a
- // clean serializable list...
- List clientObjects = new ArrayList(serverObjects.size());
-
if (!serverObjects.isEmpty()) {
- ObjectDetachOperation op = new ObjectDetachOperation(serverResolver
- .getClientEntityResolver());
- Iterator it = serverObjects.iterator();
- PrefetchTreeNode prefetchTree = serverMetadata.getPrefetchTree();
-
- while (it.hasNext()) {
- Persistent object = (Persistent) it.next();
- ObjectId id = object.getObjectId();
-
- // sanity check
- if (id == null) {
- throw new CayenneRuntimeException(
- "Server returned an object without an id: " + object);
- }
-
- // have to resolve descriptor here for every object, as
- // often a query will not have any info indicating the
- // entity type
- ClassDescriptor serverDescriptor = serverResolver.getClassDescriptor(id
- .getEntityName());
- clientObjects.add(op.detach(object, serverDescriptor, prefetchTree));
+ List<Object> rsMapping = serverMetadata.getResultSetMapping();
+
+ if (rsMapping == null) {
+ return singleObjectConversion(serverObjects);
+ }
+ else {
+ if (rsMapping.size() == 1) {
+ if (rsMapping.get(0) instanceof EntityResultSegment) {
+ return singleObjectConversion(serverObjects);
+ }
+ else {
+ // we can return a single scalar result unchanged (hmm... a scalar
+ // Object[] can also be returned unchanged)...
+ return serverObjects;
+ }
+ }
+ else {
+ return processMixedResult(serverObjects, rsMapping);
+ }
}
}
+ return new ArrayList<Object>(3);
+ }
+
+ private List<Object[]> processMixedResult(
+ List<Object[]> serverObjects,
+ List<Object> rsMapping) {
+
+ // must clone the list to ensure we do not mess up the server list that can be
+ // used elsewhere (e.g. it can be cached).
+ List<Object[]> clientObjects = new ArrayList<Object[]>(serverObjects.size());
+
+ ObjectDetachOperation op = new ObjectDetachOperation(serverResolver
+ .getClientEntityResolver());
+ int width = rsMapping.size();
+
+ for (Object[] serverObject : serverObjects) {
+
+ Object[] clientObject = new Object[width];
+
+ for (int i = 0; i < width; i++) {
+ if (rsMapping.get(i) instanceof EntityResultSegment) {
+
+ clientObject[i] = convertSingleObject(serverMetadata
+ .getPrefetchTree(), op, serverObject[i]);
+ }
+ else {
+ clientObject[i] = serverObject[i];
+ }
+ }
+
+ clientObjects.add(clientObject);
+ }
+
return clientObjects;
}
+ private List<?> singleObjectConversion(List<?> serverObjects) {
+
+ // must clone the list to ensure we do not mess up the server list that can be
+ // used elsewhere (e.g. it can be cached).
+ List<Object> clientObjects = new ArrayList<Object>(serverObjects.size());
+
+ ObjectDetachOperation op = new ObjectDetachOperation(serverResolver
+ .getClientEntityResolver());
+
+ PrefetchTreeNode prefetchTree = serverMetadata.getPrefetchTree();
+
+ for (Object serverObject : serverObjects) {
+ clientObjects.add(convertSingleObject(prefetchTree, op, serverObject));
+ }
+
+ return clientObjects;
+ }
+
+ private Object convertSingleObject(
+ PrefetchTreeNode prefetchTree,
+ ObjectDetachOperation op,
+ Object serverObject) {
+
+ Persistent object = (Persistent) serverObject;
+ ObjectId id = object.getObjectId();
+
+ // sanity check
+ if (id == null) {
+ throw new CayenneRuntimeException("Server returned an object without an id: "
+ + object);
+ }
+
+ // have to resolve descriptor here for every object, as
+ // often a query will not have any info indicating the
+ // entity type
+ ClassDescriptor serverDescriptor = serverResolver.getClassDescriptor(id
+ .getEntityName());
+
+ return op.detach(object, serverDescriptor, prefetchTree);
+ }
+
}
Modified: cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/remote/ClientChannel.java
URL: http://svn.apache.org/viewvc/cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/remote/ClientChannel.java?rev=962674&r1=962673&r2=962674&view=diff
==============================================================================
--- cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/remote/ClientChannel.java (original)
+++ cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/remote/ClientChannel.java Fri Jul 9 19:58:13 2010
@@ -36,6 +36,7 @@ import org.apache.cayenne.graph.GraphDif
import org.apache.cayenne.graph.GraphDiffCompressor;
import org.apache.cayenne.graph.GraphEvent;
import org.apache.cayenne.map.EntityResolver;
+import org.apache.cayenne.query.EntityResultSegment;
import org.apache.cayenne.query.Query;
import org.apache.cayenne.query.QueryMetadata;
import org.apache.cayenne.reflect.ClassDescriptor;
@@ -129,32 +130,26 @@ public class ClientChannel implements Da
if (response.isList()) {
List objects = response.currentList();
-
+ DeepMergeOperation merger = new DeepMergeOperation(context);
if (!objects.isEmpty()) {
-
- DeepMergeOperation merger = new DeepMergeOperation(context);
-
- // subclass descriptors will be resolved on the fly... here
- // find objects base descriptor.
- ListIterator it = objects.listIterator();
- while (it.hasNext()) {
- Persistent object = (Persistent) it.next();
- ObjectId id = object.getObjectId();
-
- // sanity check
- if (id == null) {
- throw new CayenneRuntimeException(
- "Server returned an object without an id: "
- + object);
+ List<Object> rsMapping = info.getResultSetMapping();
+ if (rsMapping == null) {
+ convertSingleObjects(resolver, objects, merger);
+ }
+ else {
+ if (rsMapping.size() == 1) {
+ if (rsMapping.get(0) instanceof EntityResultSegment) {
+ convertSingleObjects(resolver, objects, merger);
+ }
}
+ else {
+ processMixedResult(
+ resolver,
+ objects,
+ merger,
+ rsMapping);
- // have to resolve descriptor here for every object, as
- // often a query will not have any info indicating the
- // entity type
- ClassDescriptor descriptor = resolver
- .getClassDescriptor(id.getEntityName());
-
- it.set(merger.merge(object, descriptor));
+ }
}
}
}
@@ -165,6 +160,54 @@ public class ClientChannel implements Da
return response;
}
+ private void processMixedResult(
+ EntityResolver resolver,
+ List<Object[]> objects,
+ DeepMergeOperation merger,
+ List<Object> rsMapping) {
+
+ int width = rsMapping.size();
+ for (int i = 0; i < width; i++) {
+ if (rsMapping.get(i) instanceof EntityResultSegment) {
+ for (Object[] object : objects) {
+ object[i] = convertObject(resolver, merger, (Persistent) object[i]);
+ }
+ }
+ }
+ }
+
+ private void convertSingleObjects(
+ EntityResolver resolver,
+ List objects,
+ DeepMergeOperation merger) {
+
+ ListIterator it = objects.listIterator();
+ while (it.hasNext()) {
+ Object next = it.next();
+ it.set(convertObject(resolver, merger, (Persistent) next));
+ }
+ }
+
+ private Object convertObject(
+ EntityResolver resolver,
+ DeepMergeOperation merger,
+ Persistent object) {
+
+ ObjectId id = object.getObjectId();
+
+ // sanity check
+ if (id == null) {
+ throw new CayenneRuntimeException("Server returned an object without an id: "
+ + object);
+ }
+
+ // have to resolve descriptor here for every object, as often a query will not
+ // have any info indicating the entity type
+ ClassDescriptor descriptor = resolver.getClassDescriptor(id.getEntityName());
+
+ return merger.merge(object, descriptor);
+ }
+
public GraphDiff onSync(
ObjectContext originatingContext,
GraphDiff changes,
Modified: cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/CayenneContextEJBQLTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/CayenneContextEJBQLTest.java?rev=962674&r1=962673&r2=962674&view=diff
==============================================================================
--- cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/CayenneContextEJBQLTest.java (original)
+++ cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/CayenneContextEJBQLTest.java Fri Jul 9 19:58:13 2010
@@ -46,7 +46,7 @@ public class CayenneContextEJBQLTest ext
public void testEJBQLSelect() throws Exception {
createTestData("testEJBQLSelect");
-
+
DataContext context = createDataContext();
ClientServerChannel clientServerChannel = new ClientServerChannel(context);
UnitLocalConnection connection = new UnitLocalConnection(
@@ -58,6 +58,43 @@ public class CayenneContextEJBQLTest ext
EJBQLQuery query = new EJBQLQuery("SELECT a FROM MtTable1 a");
List<ClientMtTable1> results = clientContext.performQuery(query);
+
+ assertEquals(2, results.size());
+ }
+
+ public void testEJBQLSelectScalar() throws Exception {
+ createTestData("testEJBQLSelect");
+ DataContext context = createDataContext();
+ ClientServerChannel clientServerChannel = new ClientServerChannel(context);
+ UnitLocalConnection connection = new UnitLocalConnection(
+ clientServerChannel,
+ LocalConnection.HESSIAN_SERIALIZATION);
+ ClientChannel channel = new ClientChannel(connection);
+ CayenneContext clientContext = new CayenneContext(channel);
+
+ EJBQLQuery query = new EJBQLQuery("SELECT COUNT(a) FROM MtTable1 a");
+
+ List<Long> results = clientContext.performQuery(query);
+ assertEquals(Long.valueOf(2), results.get(0));
+ }
+
+ public void testEJBQLSelectMixed() throws Exception {
+ createTestData("testEJBQLSelect");
+ DataContext context = createDataContext();
+ ClientServerChannel clientServerChannel = new ClientServerChannel(context);
+ UnitLocalConnection connection = new UnitLocalConnection(
+ clientServerChannel,
+ LocalConnection.HESSIAN_SERIALIZATION);
+ ClientChannel channel = new ClientChannel(connection);
+ CayenneContext clientContext = new CayenneContext(channel);
+
+ EJBQLQuery query = new EJBQLQuery(
+ "SELECT COUNT(a), a, a.serverAttribute1 FROM MtTable1 a Group By a");
+
+ List<Object[]> results = clientContext.performQuery(query);
assertEquals(2, results.size());
+ assertEquals(Long.valueOf(1), results.get(0)[0]);
+ assertTrue(results.get(0)[1] instanceof ClientMtTable1);
+ assertEquals("s1", results.get(0)[2]);
}
}