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 2013/07/10 18:12:58 UTC
svn commit: r1501820 - in
/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src:
main/java/org/apache/cayenne/access/ test/java/org/apache/cayenne/access/
Author: aadamchik
Date: Wed Jul 10 16:12:57 2013
New Revision: 1501820
URL: http://svn.apache.org/r1501820
Log:
CAY-1695 Unexpected null value in bidirectional one-to-one prefetch
more unit tests
refactoring to support joint prefetches
Added:
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/PrefetchObjectResolver.java
Modified:
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/HierarchicalObjectResolverNode.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/test/java/org/apache/cayenne/access/DataContextPrefetchTest.java
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/HierarchicalObjectResolverNode.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/HierarchicalObjectResolverNode.java?rev=1501820&r1=1501819&r2=1501820&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/HierarchicalObjectResolverNode.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/HierarchicalObjectResolverNode.java Wed Jul 10 16:12:57 2013
@@ -22,23 +22,19 @@ import java.util.ArrayList;
import java.util.List;
import org.apache.cayenne.CayenneRuntimeException;
-import org.apache.cayenne.DataObject;
import org.apache.cayenne.DataRow;
import org.apache.cayenne.ObjectId;
import org.apache.cayenne.Persistent;
-import org.apache.cayenne.graph.GraphManager;
import org.apache.cayenne.reflect.ClassDescriptor;
-class HierarchicalObjectResolverNode extends ObjectResolver {
+class HierarchicalObjectResolverNode extends PrefetchObjectResolver {
private PrefetchProcessorNode node;
- private long txStartRowVersion;
HierarchicalObjectResolverNode(PrefetchProcessorNode node, DataContext context, ClassDescriptor descriptor,
boolean refresh, long txStartRowVersion) {
- super(context, descriptor, refresh);
+ super(context, descriptor, refresh, txStartRowVersion);
this.node = node;
- this.txStartRowVersion = txStartRowVersion;
}
@Override
@@ -50,7 +46,6 @@ class HierarchicalObjectResolverNode ext
List<Persistent> results = new ArrayList<Persistent>(rows.size());
- GraphManager graphManager = context.getGraphManager();
for (DataRow row : rows) {
// determine entity to use
@@ -61,24 +56,9 @@ class HierarchicalObjectResolverNode ext
// has all needed metadata already cached.
ObjectId anId = createObjectId(row, classDescriptor.getEntity(), null);
- // skip processing of objects that were already processed in this
- // transaction, either by this node or by some other node...
- // added per CAY-1695 ..
-
- // TODO: is it going to have any side effects? It is run from the
- // synchronized block, so I guess other threads can't stick their
- // versions of this object in here?
- // TODO: also this logic implies that main rows are always fetched
- // first... I guess this has to stay true if prefetching is
- // involved.
-
- Persistent object = (Persistent) graphManager.getNode(anId);
- if (object == null || ((DataObject) object).getSnapshotVersion() < txStartRowVersion) {
- object = objectFromDataRow(row, anId, classDescriptor);
-
- if (object == null) {
- throw new CayenneRuntimeException("Can't build Object from row: " + row);
- }
+ Persistent object = objectFromDataRow(row, anId, classDescriptor);
+ if (object == null) {
+ throw new CayenneRuntimeException("Can't build Object from row: " + row);
}
// keep the dupe objects (and data rows) around, as there maybe an
Added: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/PrefetchObjectResolver.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/PrefetchObjectResolver.java?rev=1501820&view=auto
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/PrefetchObjectResolver.java (added)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/PrefetchObjectResolver.java Wed Jul 10 16:12:57 2013
@@ -0,0 +1,57 @@
+/*****************************************************************
+ * 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 org.apache.cayenne.DataObject;
+import org.apache.cayenne.DataRow;
+import org.apache.cayenne.ObjectId;
+import org.apache.cayenne.Persistent;
+import org.apache.cayenne.reflect.ClassDescriptor;
+
+/**
+ * @since 3.2
+ */
+class PrefetchObjectResolver extends ObjectResolver {
+
+ long txStartRowVersion;
+
+ public PrefetchObjectResolver(DataContext context, ClassDescriptor descriptor, boolean refresh,
+ long txStartRowVersion) {
+ super(context, descriptor, refresh);
+ this.txStartRowVersion = txStartRowVersion;
+ }
+
+ @Override
+ Persistent objectFromDataRow(DataRow row, ObjectId anId, ClassDescriptor classDescriptor) {
+ // skip processing of objects that were already processed in this
+ // transaction, either by this node or by some other node...
+ // added per CAY-1695 ..
+
+ // TODO: is it going to have any side effects? It is run from the
+ // synchronized block, so I guess other threads can't stick their
+ // versions of this object in here?
+ Persistent object = (Persistent) context.getGraphManager().getNode(anId);
+ if (object != null && ((DataObject) object).getSnapshotVersion() >= txStartRowVersion) {
+ return object;
+ }
+
+ return super.objectFromDataRow(row, anId, classDescriptor);
+ }
+
+}
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=1501820&r1=1501819&r2=1501820&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 Wed Jul 10 16:12:57 2013
@@ -173,16 +173,20 @@ final class PrefetchProcessorTreeBuilder
node.setDataRows(rows);
node.setIncoming(arc);
- if (node.getParent() != null && !node.isJointPrefetch()) {
-
- long txStartRowVersion;
- if (mainResultRows.isEmpty()) {
- txStartRowVersion = DataObject.DEFAULT_VERSION;
- } else {
- DataRow firstRow = (DataRow) mainResultRows.get(0);
- txStartRowVersion = firstRow.getVersion();
- }
-
+
+ // TODO: is txStartRowVersion guessed
+ // correctly? i.e. the main rows are always fetched
+ // first? I guess this has to stay true if prefetching is
+ // involved.
+ long txStartRowVersion;
+ if (mainResultRows.isEmpty()) {
+ txStartRowVersion = DataObject.DEFAULT_VERSION;
+ } else {
+ DataRow firstRow = (DataRow) mainResultRows.get(0);
+ txStartRowVersion = firstRow.getVersion();
+ }
+
+ if (node.getParent() != null && !node.isJointPrefetch()) {
node.setResolver(new HierarchicalObjectResolverNode(
node,
context,
@@ -191,8 +195,8 @@ final class PrefetchProcessorTreeBuilder
txStartRowVersion));
}
else {
- node.setResolver(new ObjectResolver(context, descriptor, queryMetadata
- .isRefreshingObjects()));
+ node.setResolver(new PrefetchObjectResolver(context, descriptor, queryMetadata
+ .isRefreshingObjects(), txStartRowVersion));
}
if (node.getParent() == null || node.getParent().isPhantom()) {
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/DataContextPrefetchTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/DataContextPrefetchTest.java?rev=1501820&r1=1501819&r2=1501820&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/DataContextPrefetchTest.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/DataContextPrefetchTest.java Wed Jul 10 16:12:57 2013
@@ -702,9 +702,54 @@ public class DataContextPrefetchTest ext
assertEquals(1, results.size());
Painting p0 = results.get(0);
- PaintingInfo pi0 = (PaintingInfo) p0.readProperty(Painting.TO_PAINTING_INFO.getName());
+ PaintingInfo pi0 = (PaintingInfo) p0.readPropertyDirectly(Painting.TO_PAINTING_INFO.getName());
assertNotNull(pi0);
- assertNotNull(pi0.readProperty(PaintingInfo.PAINTING.getName()));
+ assertNotNull(pi0.readPropertyDirectly(PaintingInfo.PAINTING.getName()));
+ }
+ });
+ }
+
+ public void testPrefetchPaintingOverToOneAndToMany() throws Exception {
+ createArtistWithTwoPaintingsAndTwoInfosDataSet();
+
+ SelectQuery<Painting> query = new SelectQuery<Painting>(Painting.class);
+ query.andQualifier(Painting.PAINTING_TITLE.eq("p_artist2"));
+ query.addPrefetch(Painting.TO_ARTIST.disjoint());
+ query.addPrefetch(Painting.TO_ARTIST.dot(Artist.PAINTING_ARRAY).disjoint());
+ final List<Painting> results = context.select(query);
+
+ queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
+
+ public void execute() {
+ assertEquals(1, results.size());
+
+ Painting p0 = results.get(0);
+ Artist a0 = (Artist) p0.readPropertyDirectly(Painting.TO_ARTIST.getName());
+ assertNotNull(a0);
+ List<?> paintings = (List<?>) a0.readPropertyDirectly(Artist.PAINTING_ARRAY.getName());
+ assertEquals(2, paintings.size());
+ }
+ });
+ }
+
+ public void testPrefetchToOneWithBackRelationship_Joint() throws Exception {
+ createArtistWithTwoPaintingsAndTwoInfosDataSet();
+
+ SelectQuery<Painting> query = new SelectQuery<Painting>(Painting.class);
+ query.andQualifier(Painting.PAINTING_TITLE.eq("p_artist2"));
+ query.addPrefetch(Painting.TO_PAINTING_INFO.joint());
+ query.addPrefetch(Painting.TO_PAINTING_INFO.dot(PaintingInfo.PAINTING).joint());
+ final List<Painting> results = context.select(query);
+
+ queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
+
+ public void execute() {
+ assertEquals(1, results.size());
+
+ Painting p0 = results.get(0);
+ PaintingInfo pi0 = (PaintingInfo) p0.readPropertyDirectly(Painting.TO_PAINTING_INFO.getName());
+ assertNotNull(pi0);
+ assertNotNull(pi0.readPropertyDirectly(PaintingInfo.PAINTING.getName()));
}
});
}