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 2014/11/02 08:10:21 UTC
[33/48] Installing Maven Failsafe Plugin
http://git-wip-us.apache.org/repos/asf/cayenne/blob/e42c376c/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextPerformQueryAPITest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextPerformQueryAPITest.java b/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextPerformQueryAPITest.java
deleted file mode 100644
index 5cd629e..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextPerformQueryAPITest.java
+++ /dev/null
@@ -1,228 +0,0 @@
-/*****************************************************************
- * 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.math.BigDecimal;
-import java.sql.Types;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.cayenne.Cayenne;
-import org.apache.cayenne.di.Inject;
-import org.apache.cayenne.log.JdbcEventLogger;
-import org.apache.cayenne.query.SQLTemplate;
-import org.apache.cayenne.test.jdbc.DBHelper;
-import org.apache.cayenne.test.jdbc.TableHelper;
-import org.apache.cayenne.testdo.testmap.Artist;
-import org.apache.cayenne.testdo.testmap.Painting;
-import org.apache.cayenne.tx.BaseTransaction;
-import org.apache.cayenne.tx.ExternalTransaction;
-import org.apache.cayenne.tx.Transaction;
-import org.apache.cayenne.unit.UnitDbAdapter;
-import org.apache.cayenne.unit.di.DataChannelInterceptor;
-import org.apache.cayenne.unit.di.UnitTestClosure;
-import org.apache.cayenne.unit.di.server.ServerCase;
-import org.apache.cayenne.unit.di.server.UseServerRuntime;
-
-@UseServerRuntime(ServerCase.TESTMAP_PROJECT)
-public class DataContextPerformQueryAPITest extends ServerCase {
-
- @Inject
- private DataContext context;
-
- @Inject
- private DataContext context2;
-
- @Inject
- private DBHelper dbHelper;
-
- @Inject
- private UnitDbAdapter accessStackAdapter;
-
- @Inject
- private DataChannelInterceptor queryInterceptor;
-
- @Inject
- private JdbcEventLogger jdbcEventLogger;
-
- private TableHelper tArtist;
- private TableHelper tPainting;
-
- @Override
- protected void setUpAfterInjection() throws Exception {
- dbHelper.deleteAll("PAINTING_INFO");
- dbHelper.deleteAll("PAINTING");
- dbHelper.deleteAll("ARTIST_EXHIBIT");
- dbHelper.deleteAll("ARTIST_GROUP");
- dbHelper.deleteAll("ARTIST");
- dbHelper.deleteAll("GALLERY");
- dbHelper.deleteAll("EXHIBIT");
-
- tArtist = new TableHelper(dbHelper, "ARTIST");
- tArtist.setColumns("ARTIST_ID", "ARTIST_NAME");
-
- tPainting = new TableHelper(dbHelper, "PAINTING");
- tPainting.setColumns("PAINTING_ID", "ARTIST_ID", "PAINTING_TITLE", "ESTIMATED_PRICE").setColumnTypes(
- Types.INTEGER, Types.BIGINT, Types.VARCHAR, Types.DECIMAL);
- }
-
- private void createTwoArtists() throws Exception {
- tArtist.insert(21, "artist2");
- tArtist.insert(201, "artist3");
- }
-
- private void createTwoArtistsAndTwoPaintingsDataSet() throws Exception {
- tArtist.insert(11, "artist2");
- tArtist.insert(101, "artist3");
- tPainting.insert(6, 101, "p_artist3", 1000);
- tPainting.insert(7, 11, "p_artist2", 2000);
- }
-
- public void testObjectQueryStringBoolean() throws Exception {
- createTwoArtistsAndTwoPaintingsDataSet();
-
- List<?> paintings = context.performQuery("ObjectQuery", true);
- assertNotNull(paintings);
- assertEquals(2, paintings.size());
- }
-
- public void testObjectQueryStringMapBoolean() throws Exception {
- createTwoArtistsAndTwoPaintingsDataSet();
-
- Artist a = Cayenne.objectForPK(context, Artist.class, 11);
- Map<String, Artist> parameters = Collections.singletonMap("artist", a);
-
- List<?> paintings = context2.performQuery("ObjectQuery", parameters, true);
- assertNotNull(paintings);
- assertEquals(1, paintings.size());
- }
-
- public void testProcedureQueryStringMapBoolean() throws Exception {
-
- if (!accessStackAdapter.supportsStoredProcedures()) {
- return;
- }
-
- if (!accessStackAdapter.canMakeObjectsOutOfProcedures()) {
- return;
- }
-
- createTwoArtistsAndTwoPaintingsDataSet();
-
- // fetch artist
- Map<String, String> parameters = Collections.singletonMap("aName", "artist2");
-
- List<?> artists;
-
- // Sybase blows whenever a transaction wraps a SP, so turn of
- // transactions
- Transaction t = new ExternalTransaction(jdbcEventLogger);
- BaseTransaction.bindThreadTransaction(t);
- try {
- artists = context.performQuery("ProcedureQuery", parameters, true);
- } finally {
- BaseTransaction.bindThreadTransaction(null);
- t.commit();
- }
-
- assertNotNull(artists);
- assertEquals(1, artists.size());
-
- Artist artist = (Artist) artists.get(0);
- assertEquals(11, ((Number) artist.getObjectId().getIdSnapshot().get(Artist.ARTIST_ID_PK_COLUMN)).intValue());
- }
-
- public void testNonSelectingQueryString() throws Exception {
-
- int[] counts = context.performNonSelectingQuery("NonSelectingQuery");
-
- assertNotNull(counts);
- assertEquals(1, counts.length);
- assertEquals(1, counts[0]);
-
- Painting p = Cayenne.objectForPK(context, Painting.class, 512);
- assertEquals("No Painting Like This", p.getPaintingTitle());
- }
-
- public void testNonSelectingQueryStringMap() throws Exception {
-
- Map<String, Object> parameters = new HashMap<String, Object>();
- parameters.put("id", 300);
- parameters.put("title", "Go Figure");
- parameters.put("price", new BigDecimal("22.01"));
-
- int[] counts = context.performNonSelectingQuery("ParameterizedNonSelectingQuery", parameters);
-
- assertNotNull(counts);
- assertEquals(1, counts.length);
- assertEquals(1, counts[0]);
-
- Painting p = Cayenne.objectForPK(context, Painting.class, 300);
- assertEquals("Go Figure", p.getPaintingTitle());
- }
-
- public void testPerfomQueryNonSelecting() throws Exception {
-
- Artist a = context.newObject(Artist.class);
- a.setArtistName("aa");
- context.commitChanges();
-
- SQLTemplate q = new SQLTemplate(Artist.class, "DELETE FROM ARTIST");
-
- // this way of executing a query makes no sense, but it shouldn't blow
- // either...
- List<?> result = context.performQuery(q);
-
- assertNotNull(result);
- assertEquals(0, result.size());
- }
-
- public void testObjectQueryWithLocalCache() throws Exception {
- createTwoArtists();
-
- List<?> artists = context.performQuery("QueryWithLocalCache", true);
- assertEquals(2, artists.size());
-
- queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
-
- public void execute() {
- List<?> artists1 = context.performQuery("QueryWithLocalCache", false);
- assertEquals(2, artists1.size());
- }
- });
- }
-
- public void testObjectQueryWithSharedCache() throws Exception {
- createTwoArtists();
-
- List<?> artists = context.performQuery("QueryWithSharedCache", true);
- assertEquals(2, artists.size());
-
- queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
-
- public void execute() {
- List<?> artists1 = context2.performQuery("QueryWithSharedCache", false);
- assertEquals(2, artists1.size());
- }
- });
- }
-}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/e42c376c/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextPrefetchExtras1IT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextPrefetchExtras1IT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextPrefetchExtras1IT.java
new file mode 100644
index 0000000..a6d632a
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextPrefetchExtras1IT.java
@@ -0,0 +1,84 @@
+/*****************************************************************
+ * 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.ObjectContext;
+import org.apache.cayenne.PersistenceState;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.query.SelectQuery;
+import org.apache.cayenne.test.jdbc.DBHelper;
+import org.apache.cayenne.test.jdbc.TableHelper;
+import org.apache.cayenne.testdo.testmap.Painting;
+import org.apache.cayenne.testdo.testmap.PaintingInfo;
+import org.apache.cayenne.unit.di.server.ServerCase;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+
+import java.util.List;
+
+/**
+ * A test case for CAY-788.
+ */
+@UseServerRuntime(ServerCase.TESTMAP_PROJECT)
+public class DataContextPrefetchExtras1IT extends ServerCase {
+
+ @Inject
+ protected ObjectContext context;
+
+ @Inject
+ protected DBHelper dbHelper;
+
+ @Override
+ protected void setUpAfterInjection() throws Exception {
+ dbHelper.deleteAll("PAINTING_INFO");
+ dbHelper.deleteAll("PAINTING");
+ dbHelper.deleteAll("ARTIST_EXHIBIT");
+ dbHelper.deleteAll("ARTIST_GROUP");
+ dbHelper.deleteAll("ARTIST");
+ }
+
+ protected void createDataSet() throws Exception {
+
+ TableHelper tPainting = new TableHelper(dbHelper, "PAINTING");
+ tPainting.setColumns("PAINTING_ID", "PAINTING_TITLE");
+
+ TableHelper tPaintingInfo = new TableHelper(dbHelper, "PAINTING_INFO");
+ tPaintingInfo.setColumns("PAINTING_ID", "TEXT_REVIEW");
+
+ for (int i = 1; i <= 10; i++) {
+ tPainting.insert(i, "P" + i);
+ tPaintingInfo.insert(i, "Review #" + i);
+ }
+ }
+
+ public void testPrefetchToOne() throws Exception {
+ createDataSet();
+
+ SelectQuery query = new SelectQuery(Painting.class);
+ query.addPrefetch(Painting.TO_PAINTING_INFO_PROPERTY);
+
+ List<Painting> objects = context.performQuery(query);
+ assertTrue(!objects.isEmpty());
+ for (Painting p : objects) {
+ PaintingInfo pi = p.getToPaintingInfo();
+ assertEquals(PersistenceState.COMMITTED, p.getPersistenceState());
+ assertEquals(PersistenceState.COMMITTED, pi.getPersistenceState());
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/e42c376c/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextPrefetchExtras1Test.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextPrefetchExtras1Test.java b/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextPrefetchExtras1Test.java
deleted file mode 100644
index e58cbd1..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextPrefetchExtras1Test.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*****************************************************************
- * 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.List;
-
-import org.apache.cayenne.ObjectContext;
-import org.apache.cayenne.PersistenceState;
-import org.apache.cayenne.di.Inject;
-import org.apache.cayenne.query.SelectQuery;
-import org.apache.cayenne.test.jdbc.DBHelper;
-import org.apache.cayenne.test.jdbc.TableHelper;
-import org.apache.cayenne.testdo.testmap.Painting;
-import org.apache.cayenne.testdo.testmap.PaintingInfo;
-import org.apache.cayenne.unit.di.server.ServerCase;
-import org.apache.cayenne.unit.di.server.UseServerRuntime;
-
-/**
- * A test case for CAY-788.
- */
-@UseServerRuntime(ServerCase.TESTMAP_PROJECT)
-public class DataContextPrefetchExtras1Test extends ServerCase {
-
- @Inject
- protected ObjectContext context;
-
- @Inject
- protected DBHelper dbHelper;
-
- @Override
- protected void setUpAfterInjection() throws Exception {
- dbHelper.deleteAll("PAINTING_INFO");
- dbHelper.deleteAll("PAINTING");
- dbHelper.deleteAll("ARTIST_EXHIBIT");
- dbHelper.deleteAll("ARTIST_GROUP");
- dbHelper.deleteAll("ARTIST");
- }
-
- protected void createDataSet() throws Exception {
-
- TableHelper tPainting = new TableHelper(dbHelper, "PAINTING");
- tPainting.setColumns("PAINTING_ID", "PAINTING_TITLE");
-
- TableHelper tPaintingInfo = new TableHelper(dbHelper, "PAINTING_INFO");
- tPaintingInfo.setColumns("PAINTING_ID", "TEXT_REVIEW");
-
- for (int i = 1; i <= 10; i++) {
- tPainting.insert(i, "P" + i);
- tPaintingInfo.insert(i, "Review #" + i);
- }
- }
-
- public void testPrefetchToOne() throws Exception {
- createDataSet();
-
- SelectQuery query = new SelectQuery(Painting.class);
- query.addPrefetch(Painting.TO_PAINTING_INFO_PROPERTY);
-
- List<Painting> objects = context.performQuery(query);
- assertTrue(!objects.isEmpty());
- for (Painting p : objects) {
- PaintingInfo pi = p.getToPaintingInfo();
- assertEquals(PersistenceState.COMMITTED, p.getPersistenceState());
- assertEquals(PersistenceState.COMMITTED, pi.getPersistenceState());
- }
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/e42c376c/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextPrefetchExtrasIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextPrefetchExtrasIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextPrefetchExtrasIT.java
new file mode 100644
index 0000000..2676819
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextPrefetchExtrasIT.java
@@ -0,0 +1,174 @@
+/*****************************************************************
+ * 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.CayenneDataObject;
+import org.apache.cayenne.DataObject;
+import org.apache.cayenne.ObjectContext;
+import org.apache.cayenne.PersistenceState;
+import org.apache.cayenne.ValueHolder;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.ExpressionFactory;
+import org.apache.cayenne.query.SelectQuery;
+import org.apache.cayenne.query.SortOrder;
+import org.apache.cayenne.test.jdbc.DBHelper;
+import org.apache.cayenne.test.jdbc.TableHelper;
+import org.apache.cayenne.testdo.testmap.CharFkTestEntity;
+import org.apache.cayenne.testdo.testmap.CharPkTestEntity;
+import org.apache.cayenne.testdo.testmap.CompoundFkTestEntity;
+import org.apache.cayenne.testdo.testmap.CompoundPkTestEntity;
+import org.apache.cayenne.unit.di.server.ServerCase;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+
+import java.util.List;
+
+/**
+ * Test prefetching of various obscure cases.
+ */
+@UseServerRuntime(ServerCase.TESTMAP_PROJECT)
+public class DataContextPrefetchExtrasIT extends ServerCase {
+
+ @Inject
+ protected ObjectContext context;
+
+ @Inject
+ protected DBHelper dbHelper;
+
+ protected TableHelper tCharPkTest;
+ protected TableHelper tCharFkTest;
+ protected TableHelper tCompoundPkTest;
+ protected TableHelper tCompoundFkTest;
+
+ @Override
+ protected void setUpAfterInjection() throws Exception {
+ dbHelper.deleteAll("CHAR_FK_TEST");
+ dbHelper.deleteAll("CHAR_PK_TEST");
+
+ dbHelper.deleteAll("COMPOUND_FK_TEST");
+ dbHelper.deleteAll("COMPOUND_PK_TEST");
+
+ tCharPkTest = new TableHelper(dbHelper, "CHAR_PK_TEST");
+ tCharPkTest.setColumns("PK_COL", "OTHER_COL");
+
+ tCharFkTest = new TableHelper(dbHelper, "CHAR_FK_TEST");
+ tCharFkTest.setColumns("PK", "FK_COL", "NAME");
+
+ tCompoundPkTest = new TableHelper(dbHelper, "COMPOUND_PK_TEST");
+ tCompoundPkTest.setColumns("KEY1", "KEY2", "NAME");
+
+ tCompoundFkTest = new TableHelper(dbHelper, "COMPOUND_FK_TEST");
+ tCompoundFkTest.setColumns("PKEY", "F_KEY1", "F_KEY2", "NAME");
+ }
+
+ protected void createPrefetchToManyOnCharKeyDataSet() throws Exception {
+ tCharPkTest.insert("k1", "n1");
+ tCharPkTest.insert("k2", "n2");
+
+ tCharFkTest.insert(1, "k1", "fn1");
+ tCharFkTest.insert(2, "k1", "fn2");
+ tCharFkTest.insert(3, "k2", "fn3");
+ tCharFkTest.insert(4, "k2", "fn4");
+ tCharFkTest.insert(5, "k1", "fn5");
+ }
+
+ protected void createCompoundDataSet() throws Exception {
+ tCompoundPkTest.insert("101", "201", "CPK1");
+ tCompoundPkTest.insert("102", "202", "CPK2");
+ tCompoundPkTest.insert("103", "203", "CPK3");
+
+ tCompoundFkTest.insert(301, "102", "202", "CFK1");
+ tCompoundFkTest.insert(302, "102", "202", "CFK2");
+ tCompoundFkTest.insert(303, "101", "201", "CFK3");
+ }
+
+ public void testPrefetchToManyOnCharKey() throws Exception {
+ createPrefetchToManyOnCharKeyDataSet();
+
+ SelectQuery q = new SelectQuery(CharPkTestEntity.class);
+ q.addPrefetch("charFKs");
+ q.addOrdering(CharPkTestEntity.OTHER_COL_PROPERTY, SortOrder.ASCENDING);
+
+ List<?> pks = context.performQuery(q);
+ assertEquals(2, pks.size());
+
+ CharPkTestEntity pk1 = (CharPkTestEntity) pks.get(0);
+ assertEquals("n1", pk1.getOtherCol());
+ List<?> toMany = (List<?>) pk1.readPropertyDirectly("charFKs");
+ assertNotNull(toMany);
+ assertFalse(((ValueHolder) toMany).isFault());
+ assertEquals(3, toMany.size());
+
+ CharFkTestEntity fk1 = (CharFkTestEntity) toMany.get(0);
+ assertEquals(PersistenceState.COMMITTED, fk1.getPersistenceState());
+ assertSame(pk1, fk1.getToCharPK());
+ }
+
+ /**
+ * Tests to-one prefetching over relationships with compound keys.
+ */
+ public void testPrefetch10() throws Exception {
+ createCompoundDataSet();
+
+ Expression e = ExpressionFactory.matchExp("name", "CFK2");
+ SelectQuery q = new SelectQuery(CompoundFkTestEntity.class, e);
+ q.addPrefetch("toCompoundPk");
+
+ List<?> objects = context.performQuery(q);
+ assertEquals(1, objects.size());
+ CayenneDataObject fk1 = (CayenneDataObject) objects.get(0);
+
+ Object toOnePrefetch = fk1.readNestedProperty("toCompoundPk");
+ assertNotNull(toOnePrefetch);
+ assertTrue(
+ "Expected DataObject, got: " + toOnePrefetch.getClass().getName(),
+ toOnePrefetch instanceof DataObject);
+
+ DataObject pk1 = (DataObject) toOnePrefetch;
+ assertEquals(PersistenceState.COMMITTED, pk1.getPersistenceState());
+ assertEquals("CPK2", pk1.readPropertyDirectly("name"));
+ }
+
+ /**
+ * Tests to-many prefetching over relationships with compound keys.
+ */
+ public void testPrefetch11() throws Exception {
+ createCompoundDataSet();
+
+ Expression e = ExpressionFactory.matchExp("name", "CPK2");
+ SelectQuery q = new SelectQuery(CompoundPkTestEntity.class, e);
+ q.addPrefetch("compoundFkArray");
+
+ List<?> pks = context.performQuery(q);
+ assertEquals(1, pks.size());
+ CayenneDataObject pk1 = (CayenneDataObject) pks.get(0);
+
+ List<?> toMany = (List<?>) pk1.readPropertyDirectly("compoundFkArray");
+ assertNotNull(toMany);
+ assertFalse(((ValueHolder) toMany).isFault());
+ assertEquals(2, toMany.size());
+
+ CayenneDataObject fk1 = (CayenneDataObject) toMany.get(0);
+ assertEquals(PersistenceState.COMMITTED, fk1.getPersistenceState());
+
+ CayenneDataObject fk2 = (CayenneDataObject) toMany.get(1);
+ assertEquals(PersistenceState.COMMITTED, fk2.getPersistenceState());
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/e42c376c/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextPrefetchExtrasTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextPrefetchExtrasTest.java b/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextPrefetchExtrasTest.java
deleted file mode 100644
index 7d4df84..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextPrefetchExtrasTest.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*****************************************************************
- * 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.List;
-
-import org.apache.cayenne.CayenneDataObject;
-import org.apache.cayenne.DataObject;
-import org.apache.cayenne.ObjectContext;
-import org.apache.cayenne.PersistenceState;
-import org.apache.cayenne.ValueHolder;
-import org.apache.cayenne.di.Inject;
-import org.apache.cayenne.exp.Expression;
-import org.apache.cayenne.exp.ExpressionFactory;
-import org.apache.cayenne.query.SelectQuery;
-import org.apache.cayenne.query.SortOrder;
-import org.apache.cayenne.test.jdbc.DBHelper;
-import org.apache.cayenne.test.jdbc.TableHelper;
-import org.apache.cayenne.testdo.testmap.CharFkTestEntity;
-import org.apache.cayenne.testdo.testmap.CharPkTestEntity;
-import org.apache.cayenne.testdo.testmap.CompoundFkTestEntity;
-import org.apache.cayenne.testdo.testmap.CompoundPkTestEntity;
-import org.apache.cayenne.unit.di.server.ServerCase;
-import org.apache.cayenne.unit.di.server.UseServerRuntime;
-
-/**
- * Test prefetching of various obscure cases.
- */
-@UseServerRuntime(ServerCase.TESTMAP_PROJECT)
-public class DataContextPrefetchExtrasTest extends ServerCase {
-
- @Inject
- protected ObjectContext context;
-
- @Inject
- protected DBHelper dbHelper;
-
- protected TableHelper tCharPkTest;
- protected TableHelper tCharFkTest;
- protected TableHelper tCompoundPkTest;
- protected TableHelper tCompoundFkTest;
-
- @Override
- protected void setUpAfterInjection() throws Exception {
- dbHelper.deleteAll("CHAR_FK_TEST");
- dbHelper.deleteAll("CHAR_PK_TEST");
-
- dbHelper.deleteAll("COMPOUND_FK_TEST");
- dbHelper.deleteAll("COMPOUND_PK_TEST");
-
- tCharPkTest = new TableHelper(dbHelper, "CHAR_PK_TEST");
- tCharPkTest.setColumns("PK_COL", "OTHER_COL");
-
- tCharFkTest = new TableHelper(dbHelper, "CHAR_FK_TEST");
- tCharFkTest.setColumns("PK", "FK_COL", "NAME");
-
- tCompoundPkTest = new TableHelper(dbHelper, "COMPOUND_PK_TEST");
- tCompoundPkTest.setColumns("KEY1", "KEY2", "NAME");
-
- tCompoundFkTest = new TableHelper(dbHelper, "COMPOUND_FK_TEST");
- tCompoundFkTest.setColumns("PKEY", "F_KEY1", "F_KEY2", "NAME");
- }
-
- protected void createPrefetchToManyOnCharKeyDataSet() throws Exception {
- tCharPkTest.insert("k1", "n1");
- tCharPkTest.insert("k2", "n2");
-
- tCharFkTest.insert(1, "k1", "fn1");
- tCharFkTest.insert(2, "k1", "fn2");
- tCharFkTest.insert(3, "k2", "fn3");
- tCharFkTest.insert(4, "k2", "fn4");
- tCharFkTest.insert(5, "k1", "fn5");
- }
-
- protected void createCompoundDataSet() throws Exception {
- tCompoundPkTest.insert("101", "201", "CPK1");
- tCompoundPkTest.insert("102", "202", "CPK2");
- tCompoundPkTest.insert("103", "203", "CPK3");
-
- tCompoundFkTest.insert(301, "102", "202", "CFK1");
- tCompoundFkTest.insert(302, "102", "202", "CFK2");
- tCompoundFkTest.insert(303, "101", "201", "CFK3");
- }
-
- public void testPrefetchToManyOnCharKey() throws Exception {
- createPrefetchToManyOnCharKeyDataSet();
-
- SelectQuery q = new SelectQuery(CharPkTestEntity.class);
- q.addPrefetch("charFKs");
- q.addOrdering(CharPkTestEntity.OTHER_COL_PROPERTY, SortOrder.ASCENDING);
-
- List<?> pks = context.performQuery(q);
- assertEquals(2, pks.size());
-
- CharPkTestEntity pk1 = (CharPkTestEntity) pks.get(0);
- assertEquals("n1", pk1.getOtherCol());
- List<?> toMany = (List<?>) pk1.readPropertyDirectly("charFKs");
- assertNotNull(toMany);
- assertFalse(((ValueHolder) toMany).isFault());
- assertEquals(3, toMany.size());
-
- CharFkTestEntity fk1 = (CharFkTestEntity) toMany.get(0);
- assertEquals(PersistenceState.COMMITTED, fk1.getPersistenceState());
- assertSame(pk1, fk1.getToCharPK());
- }
-
- /**
- * Tests to-one prefetching over relationships with compound keys.
- */
- public void testPrefetch10() throws Exception {
- createCompoundDataSet();
-
- Expression e = ExpressionFactory.matchExp("name", "CFK2");
- SelectQuery q = new SelectQuery(CompoundFkTestEntity.class, e);
- q.addPrefetch("toCompoundPk");
-
- List<?> objects = context.performQuery(q);
- assertEquals(1, objects.size());
- CayenneDataObject fk1 = (CayenneDataObject) objects.get(0);
-
- Object toOnePrefetch = fk1.readNestedProperty("toCompoundPk");
- assertNotNull(toOnePrefetch);
- assertTrue(
- "Expected DataObject, got: " + toOnePrefetch.getClass().getName(),
- toOnePrefetch instanceof DataObject);
-
- DataObject pk1 = (DataObject) toOnePrefetch;
- assertEquals(PersistenceState.COMMITTED, pk1.getPersistenceState());
- assertEquals("CPK2", pk1.readPropertyDirectly("name"));
- }
-
- /**
- * Tests to-many prefetching over relationships with compound keys.
- */
- public void testPrefetch11() throws Exception {
- createCompoundDataSet();
-
- Expression e = ExpressionFactory.matchExp("name", "CPK2");
- SelectQuery q = new SelectQuery(CompoundPkTestEntity.class, e);
- q.addPrefetch("compoundFkArray");
-
- List<?> pks = context.performQuery(q);
- assertEquals(1, pks.size());
- CayenneDataObject pk1 = (CayenneDataObject) pks.get(0);
-
- List<?> toMany = (List<?>) pk1.readPropertyDirectly("compoundFkArray");
- assertNotNull(toMany);
- assertFalse(((ValueHolder) toMany).isFault());
- assertEquals(2, toMany.size());
-
- CayenneDataObject fk1 = (CayenneDataObject) toMany.get(0);
- assertEquals(PersistenceState.COMMITTED, fk1.getPersistenceState());
-
- CayenneDataObject fk2 = (CayenneDataObject) toMany.get(1);
- assertEquals(PersistenceState.COMMITTED, fk2.getPersistenceState());
- }
-}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/e42c376c/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextPrefetchIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextPrefetchIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextPrefetchIT.java
new file mode 100644
index 0000000..39525fd
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextPrefetchIT.java
@@ -0,0 +1,801 @@
+/*****************************************************************
+ * 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.Cayenne;
+import org.apache.cayenne.PersistenceState;
+import org.apache.cayenne.ValueHolder;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.ExpressionFactory;
+import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.map.ObjEntity;
+import org.apache.cayenne.map.ObjRelationship;
+import org.apache.cayenne.query.PrefetchTreeNode;
+import org.apache.cayenne.query.QueryCacheStrategy;
+import org.apache.cayenne.query.SelectQuery;
+import org.apache.cayenne.query.SortOrder;
+import org.apache.cayenne.test.jdbc.DBHelper;
+import org.apache.cayenne.test.jdbc.TableHelper;
+import org.apache.cayenne.testdo.testmap.ArtGroup;
+import org.apache.cayenne.testdo.testmap.Artist;
+import org.apache.cayenne.testdo.testmap.ArtistExhibit;
+import org.apache.cayenne.testdo.testmap.Painting;
+import org.apache.cayenne.testdo.testmap.PaintingInfo;
+import org.apache.cayenne.unit.di.DataChannelInterceptor;
+import org.apache.cayenne.unit.di.UnitTestClosure;
+import org.apache.cayenne.unit.di.server.ServerCase;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+
+import java.sql.Timestamp;
+import java.sql.Types;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@UseServerRuntime(ServerCase.TESTMAP_PROJECT)
+public class DataContextPrefetchIT extends ServerCase {
+
+ @Inject
+ protected DataContext context;
+
+ @Inject
+ protected DBHelper dbHelper;
+
+ @Inject
+ protected DataChannelInterceptor queryInterceptor;
+
+ protected TableHelper tArtist;
+ protected TableHelper tPainting;
+ protected TableHelper tPaintingInfo;
+ protected TableHelper tExhibit;
+ protected TableHelper tGallery;
+ protected TableHelper tArtistExhibit;
+ protected TableHelper tArtistGroup;
+ protected TableHelper tArtGroup;
+
+
+ @Override
+ protected void setUpAfterInjection() throws Exception {
+ dbHelper.deleteAll("PAINTING_INFO");
+ dbHelper.deleteAll("PAINTING");
+ dbHelper.deleteAll("ARTIST_EXHIBIT");
+ dbHelper.deleteAll("ARTIST_GROUP");
+ dbHelper.deleteAll("ARTGROUP");
+
+ dbHelper.deleteAll("ARTIST");
+ dbHelper.deleteAll("EXHIBIT");
+ dbHelper.deleteAll("GALLERY");
+
+ tArtist = new TableHelper(dbHelper, "ARTIST");
+ tArtist.setColumns("ARTIST_ID", "ARTIST_NAME");
+
+ tPainting = new TableHelper(dbHelper, "PAINTING");
+ tPainting.setColumns("PAINTING_ID", "PAINTING_TITLE", "ARTIST_ID", "ESTIMATED_PRICE").setColumnTypes(
+ Types.INTEGER, Types.VARCHAR, Types.BIGINT, Types.DECIMAL);
+
+ tPaintingInfo = new TableHelper(dbHelper, "PAINTING_INFO");
+ tPaintingInfo.setColumns("PAINTING_ID", "TEXT_REVIEW");
+
+ tExhibit = new TableHelper(dbHelper, "EXHIBIT");
+ tExhibit.setColumns("EXHIBIT_ID", "GALLERY_ID", "OPENING_DATE", "CLOSING_DATE");
+
+ tArtistExhibit = new TableHelper(dbHelper, "ARTIST_EXHIBIT");
+ tArtistExhibit.setColumns("ARTIST_ID", "EXHIBIT_ID");
+
+ tGallery = new TableHelper(dbHelper, "GALLERY");
+ tGallery.setColumns("GALLERY_ID", "GALLERY_NAME");
+
+ tArtistGroup = new TableHelper(dbHelper, "ARTIST_GROUP");
+ tArtistGroup.setColumns("ARTIST_ID", "GROUP_ID");
+
+ tArtGroup = new TableHelper(dbHelper, "ARTGROUP");
+ tArtGroup.setColumns("GROUP_ID", "NAME");
+ }
+
+ protected void createTwoArtistsAndTwoPaintingsDataSet() throws Exception {
+ tArtist.insert(11, "artist2");
+ tArtist.insert(101, "artist3");
+ tPainting.insert(6, "p_artist3", 101, 1000);
+ tPainting.insert(7, "p_artist2", 11, 2000);
+ }
+
+ protected void createArtistWithTwoPaintingsAndTwoInfosDataSet() throws Exception {
+ tArtist.insert(11, "artist2");
+
+ tPainting.insert(6, "p_artist2", 11, 1000);
+ tPainting.insert(7, "p_artist3", 11, 2000);
+
+ tPaintingInfo.insert(6, "xYs");
+ }
+
+ protected void createTwoArtistsWithExhibitsDataSet() throws Exception {
+ tArtist.insert(11, "artist2");
+ tArtist.insert(101, "artist3");
+
+ tGallery.insert(25, "gallery1");
+ tGallery.insert(31, "gallery2");
+ tGallery.insert(45, "gallery3");
+
+ Timestamp now = new Timestamp(System.currentTimeMillis());
+
+ tExhibit.insert(1, 25, now, now);
+ tExhibit.insert(2, 31, now, now);
+ tExhibit.insert(3, 45, now, now);
+ tExhibit.insert(4, 25, now, now);
+
+ tArtistExhibit.insert(11, 2);
+ tArtistExhibit.insert(11, 4);
+ tArtistExhibit.insert(101, 1);
+ tArtistExhibit.insert(101, 3);
+ tArtistExhibit.insert(101, 4);
+ }
+
+ public void testPrefetchToMany_ViaProperty() throws Exception {
+ createTwoArtistsAndTwoPaintingsDataSet();
+
+ SelectQuery<Artist> q = new SelectQuery<Artist>(Artist.class);
+ q.addPrefetch(Artist.PAINTING_ARRAY.disjoint());
+
+ final List<Artist> artists = context.select(q);
+
+ queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
+
+ public void execute() {
+
+ assertEquals(2, artists.size());
+
+ for (int i = 0; i < 2; i++) {
+ Artist a = artists.get(i);
+ List<?> toMany = (List<?>) a.readPropertyDirectly("paintingArray");
+ assertNotNull(toMany);
+ assertFalse(((ValueHolder) toMany).isFault());
+ assertEquals(1, toMany.size());
+
+ Painting p = (Painting) toMany.get(0);
+ assertEquals("Invalid prefetched painting:" + p, "p_" + a.getArtistName(), p.getPaintingTitle());
+ }
+ }
+ });
+ }
+
+ public void testPrefetchToMany_WithQualfier() throws Exception {
+ createTwoArtistsAndTwoPaintingsDataSet();
+
+ Map<String, Object> params = new HashMap<String, Object>();
+ params.put("name1", "artist2");
+ params.put("name2", "artist3");
+ Expression e = Expression.fromString("artistName = $name1 or artistName = $name2");
+ SelectQuery q = new SelectQuery("Artist", e.expWithParameters(params));
+ q.addPrefetch(Artist.PAINTING_ARRAY_PROPERTY);
+
+ final List<Artist> artists = context.performQuery(q);
+
+ queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
+
+ public void execute() {
+
+ assertEquals(2, artists.size());
+
+ Artist a1 = artists.get(0);
+ List<?> toMany = (List<?>) a1.readPropertyDirectly(Artist.PAINTING_ARRAY_PROPERTY);
+ assertNotNull(toMany);
+ assertFalse(((ValueHolder) toMany).isFault());
+ assertEquals(1, toMany.size());
+
+ Painting p1 = (Painting) toMany.get(0);
+ assertEquals("p_" + a1.getArtistName(), p1.getPaintingTitle());
+
+ Artist a2 = artists.get(1);
+ List<?> toMany2 = (List<?>) a2.readPropertyDirectly(Artist.PAINTING_ARRAY_PROPERTY);
+ assertNotNull(toMany2);
+ assertFalse(((ValueHolder) toMany2).isFault());
+ assertEquals(1, toMany2.size());
+
+ Painting p2 = (Painting) toMany2.get(0);
+ assertEquals("p_" + a2.getArtistName(), p2.getPaintingTitle());
+ }
+ });
+ }
+
+ public void testPrefetchToManyNoQualifier() throws Exception {
+ createTwoArtistsAndTwoPaintingsDataSet();
+
+ SelectQuery q = new SelectQuery(Artist.class);
+ q.addPrefetch(Artist.PAINTING_ARRAY_PROPERTY);
+
+ final List<Artist> artists = context.performQuery(q);
+
+ queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
+
+ public void execute() {
+
+ assertEquals(2, artists.size());
+
+ for (int i = 0; i < 2; i++) {
+ Artist a = artists.get(i);
+ List<?> toMany = (List<?>) a.readPropertyDirectly("paintingArray");
+ assertNotNull(toMany);
+ assertFalse(((ValueHolder) toMany).isFault());
+ assertEquals(1, toMany.size());
+
+ Painting p = (Painting) toMany.get(0);
+ assertEquals("Invalid prefetched painting:" + p, "p_" + a.getArtistName(), p.getPaintingTitle());
+ }
+ }
+ });
+ }
+
+ /**
+ * Test that a to-many relationship is initialized when a target entity has
+ * a compound PK only partially involved in relationship.
+ */
+ public void testPrefetchToMany_OnJoinTableDisjoinedPrefetch() throws Exception {
+
+ createTwoArtistsWithExhibitsDataSet();
+
+ SelectQuery q = new SelectQuery(Artist.class);
+ q.addPrefetch(Artist.ARTIST_EXHIBIT_ARRAY_PROPERTY).setSemantics(PrefetchTreeNode.DISJOINT_PREFETCH_SEMANTICS);
+ q.addOrdering(Artist.ARTIST_NAME_PROPERTY, SortOrder.ASCENDING);
+
+ final List<Artist> artists = context.performQuery(q);
+
+ queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
+
+ public void execute() {
+ assertEquals(2, artists.size());
+
+ Artist a1 = artists.get(0);
+ assertEquals("artist2", a1.getArtistName());
+ List<?> toMany = (List<?>) a1.readPropertyDirectly(Artist.ARTIST_EXHIBIT_ARRAY_PROPERTY);
+ assertNotNull(toMany);
+ assertFalse(((ValueHolder) toMany).isFault());
+ assertEquals(2, toMany.size());
+
+ ArtistExhibit artistExhibit = (ArtistExhibit) toMany.get(0);
+ assertEquals(PersistenceState.COMMITTED, artistExhibit.getPersistenceState());
+ assertSame(a1, artistExhibit.getToArtist());
+
+ Artist a2 = artists.get(1);
+ assertEquals("artist3", a2.getArtistName());
+ List<?> toMany2 = (List<?>) a2.readPropertyDirectly(Artist.ARTIST_EXHIBIT_ARRAY_PROPERTY);
+ assertNotNull(toMany2);
+ assertFalse(((ValueHolder) toMany2).isFault());
+ assertEquals(3, toMany2.size());
+
+ ArtistExhibit artistExhibit2 = (ArtistExhibit) toMany2.get(0);
+ assertEquals(PersistenceState.COMMITTED, artistExhibit2.getPersistenceState());
+ assertSame(a2, artistExhibit2.getToArtist());
+ }
+ });
+ }
+
+ public void testPrefetchToManyOnJoinTableJoinedPrefetch_ViaProperty() throws Exception {
+ createTwoArtistsWithExhibitsDataSet();
+
+ SelectQuery<Artist> q = new SelectQuery<Artist>(Artist.class);
+ q.addPrefetch(Artist.ARTIST_EXHIBIT_ARRAY.joint());
+ q.addOrdering(Artist.ARTIST_NAME.asc());
+
+ final List<Artist> artists = context.select(q);
+
+ queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
+
+ public void execute() {
+
+ assertEquals(2, artists.size());
+
+ Artist a1 = artists.get(0);
+ assertEquals("artist2", a1.getArtistName());
+ List<?> toMany = (List<?>) a1.readPropertyDirectly(Artist.ARTIST_EXHIBIT_ARRAY.getName());
+ assertNotNull(toMany);
+ assertFalse(((ValueHolder) toMany).isFault());
+ assertEquals(2, toMany.size());
+
+ ArtistExhibit artistExhibit = (ArtistExhibit) toMany.get(0);
+ assertEquals(PersistenceState.COMMITTED, artistExhibit.getPersistenceState());
+ assertSame(a1, artistExhibit.getToArtist());
+
+ Artist a2 = artists.get(1);
+ assertEquals("artist3", a2.getArtistName());
+ List<?> toMany2 = (List<?>) a2.readPropertyDirectly(Artist.ARTIST_EXHIBIT_ARRAY.getName());
+ assertNotNull(toMany2);
+ assertFalse(((ValueHolder) toMany2).isFault());
+ assertEquals(3, toMany2.size());
+
+ ArtistExhibit artistExhibit2 = (ArtistExhibit) toMany2.get(0);
+ assertEquals(PersistenceState.COMMITTED, artistExhibit2.getPersistenceState());
+ assertSame(a2, artistExhibit2.getToArtist());
+ }
+ });
+ }
+
+ /**
+ * Test that a to-many relationship is initialized when a target entity has
+ * a compound PK only partially involved in relationship.
+ */
+ public void testPrefetchToManyOnJoinTableJoinedPrefetch() throws Exception {
+ createTwoArtistsWithExhibitsDataSet();
+
+ SelectQuery q = new SelectQuery(Artist.class);
+ q.addPrefetch("artistExhibitArray").setSemantics(PrefetchTreeNode.JOINT_PREFETCH_SEMANTICS);
+ q.addOrdering(Artist.ARTIST_NAME_PROPERTY, SortOrder.ASCENDING);
+
+ final List<Artist> artists = context.performQuery(q);
+
+ queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
+
+ public void execute() {
+
+ assertEquals(2, artists.size());
+
+ Artist a1 = artists.get(0);
+ assertEquals("artist2", a1.getArtistName());
+ List<?> toMany = (List<?>) a1.readPropertyDirectly("artistExhibitArray");
+ assertNotNull(toMany);
+ assertFalse(((ValueHolder) toMany).isFault());
+ assertEquals(2, toMany.size());
+
+ ArtistExhibit artistExhibit = (ArtistExhibit) toMany.get(0);
+ assertEquals(PersistenceState.COMMITTED, artistExhibit.getPersistenceState());
+ assertSame(a1, artistExhibit.getToArtist());
+
+ Artist a2 = artists.get(1);
+ assertEquals("artist3", a2.getArtistName());
+ List<?> toMany2 = (List<?>) a2.readPropertyDirectly(Artist.ARTIST_EXHIBIT_ARRAY_PROPERTY);
+ assertNotNull(toMany2);
+ assertFalse(((ValueHolder) toMany2).isFault());
+ assertEquals(3, toMany2.size());
+
+ ArtistExhibit artistExhibit2 = (ArtistExhibit) toMany2.get(0);
+ assertEquals(PersistenceState.COMMITTED, artistExhibit2.getPersistenceState());
+ assertSame(a2, artistExhibit2.getToArtist());
+ }
+ });
+ }
+
+ /**
+ * Test that a to-many relationship is initialized when there is no inverse
+ * relationship
+ */
+ public void testPrefetch_ToManyNoReverse() throws Exception {
+ createTwoArtistsAndTwoPaintingsDataSet();
+
+ ObjEntity paintingEntity = context.getEntityResolver().getObjEntity(Painting.class);
+ ObjRelationship relationship = paintingEntity.getRelationship("toArtist");
+ paintingEntity.removeRelationship("toArtist");
+
+ try {
+ SelectQuery q = new SelectQuery(Artist.class);
+ q.addPrefetch(Artist.PAINTING_ARRAY_PROPERTY);
+ final List<Artist> result = context.performQuery(q);
+
+ queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
+
+ public void execute() {
+ assertFalse(result.isEmpty());
+ Artist a1 = result.get(0);
+ List<?> toMany = (List<?>) a1.readPropertyDirectly("paintingArray");
+ assertNotNull(toMany);
+ assertFalse(((ValueHolder) toMany).isFault());
+ }
+ });
+ } finally {
+ paintingEntity.addRelationship(relationship);
+ }
+ }
+
+ public void testPrefetch_ToManyNoReverseWithQualifier() throws Exception {
+ createTwoArtistsAndTwoPaintingsDataSet();
+
+ ObjEntity paintingEntity = context.getEntityResolver().getObjEntity(Painting.class);
+ ObjRelationship relationship = paintingEntity.getRelationship("toArtist");
+ paintingEntity.removeRelationship("toArtist");
+
+ try {
+
+ SelectQuery q = new SelectQuery(Artist.class);
+ q.setQualifier(ExpressionFactory.matchExp("artistName", "artist2"));
+ q.addPrefetch(Artist.PAINTING_ARRAY_PROPERTY);
+
+ final List<Artist> result = context.performQuery(q);
+
+ queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
+
+ public void execute() {
+ assertFalse(result.isEmpty());
+ Artist a1 = result.get(0);
+ List<?> toMany = (List<?>) a1.readPropertyDirectly("paintingArray");
+ assertNotNull(toMany);
+ assertFalse(((ValueHolder) toMany).isFault());
+ }
+ });
+
+ } finally {
+ paintingEntity.addRelationship(relationship);
+ }
+ }
+
+ public void testPrefetch_ToOne() throws Exception {
+ createTwoArtistsAndTwoPaintingsDataSet();
+
+ SelectQuery q = new SelectQuery(Painting.class);
+ q.addPrefetch(Painting.TO_ARTIST_PROPERTY);
+
+ final List<Painting> result = context.performQuery(q);
+
+ queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
+
+ public void execute() {
+ assertFalse(result.isEmpty());
+ Painting p1 = result.get(0);
+
+ Object toOnePrefetch = p1.readNestedProperty("toArtist");
+ assertNotNull(toOnePrefetch);
+ assertTrue("Expected Artist, got: " + toOnePrefetch.getClass().getName(),
+ toOnePrefetch instanceof Artist);
+
+ Artist a1 = (Artist) toOnePrefetch;
+ assertEquals(PersistenceState.COMMITTED, a1.getPersistenceState());
+ }
+ });
+ }
+
+ public void testPrefetch_ToOne_DbPath() throws Exception {
+ createTwoArtistsAndTwoPaintingsDataSet();
+
+ SelectQuery q = new SelectQuery(Painting.class);
+ q.addPrefetch(Painting.TO_ARTIST_PROPERTY);
+ q.andQualifier(ExpressionFactory.matchDbExp("toArtist.ARTIST_NAME", "artist2"));
+
+ List<Painting> results = context.performQuery(q);
+
+ assertEquals(1, results.size());
+ }
+
+ public void testPrefetch_ToOne_ObjPath() throws Exception {
+ createTwoArtistsAndTwoPaintingsDataSet();
+
+ SelectQuery q = new SelectQuery(Painting.class);
+ q.addPrefetch(Painting.TO_ARTIST_PROPERTY);
+ q.andQualifier(ExpressionFactory.matchExp("toArtist.artistName", "artist2"));
+
+ List<Painting> results = context.performQuery(q);
+ assertEquals(1, results.size());
+ }
+
+ public void testPrefetch_ReflexiveRelationship() throws Exception {
+ ArtGroup parent = (ArtGroup) context.newObject("ArtGroup");
+ parent.setName("parent");
+ ArtGroup child = (ArtGroup) context.newObject("ArtGroup");
+ child.setName("child");
+ child.setToParentGroup(parent);
+ context.commitChanges();
+
+ SelectQuery q = new SelectQuery("ArtGroup");
+ q.setQualifier(ExpressionFactory.matchExp("name", "child"));
+ q.addPrefetch("toParentGroup");
+
+ final List<ArtGroup> results = context.performQuery(q);
+
+ queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
+
+ public void execute() {
+ assertEquals(1, results.size());
+
+ ArtGroup fetchedChild = results.get(0);
+ // The parent must be fully fetched, not just HOLLOW (a fault)
+ assertEquals(PersistenceState.COMMITTED, fetchedChild.getToParentGroup().getPersistenceState());
+ }
+ });
+ }
+
+ public void testPrefetch_ToOneWithQualifierOverlappingPrefetchPath() throws Exception {
+ createTwoArtistsAndTwoPaintingsDataSet();
+
+ Expression exp = ExpressionFactory.matchExp("toArtist.artistName", "artist3");
+
+ SelectQuery q = new SelectQuery(Painting.class, exp);
+ q.addPrefetch(Painting.TO_ARTIST_PROPERTY);
+
+ final List<Painting> results = context.performQuery(q);
+
+ queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
+
+ public void execute() {
+ assertEquals(1, results.size());
+
+ Painting painting = results.get(0);
+
+ // The parent must be fully fetched, not just HOLLOW (a fault)
+ assertEquals(PersistenceState.COMMITTED, painting.getToArtist().getPersistenceState());
+ }
+ });
+ }
+
+ public void testPrefetch_ToOneWith_OuterJoinFlattenedQualifier() throws Exception {
+
+ tArtGroup.insert(1, "AG");
+ tArtist.insert(11, "artist2");
+ tArtist.insert(101, "artist3");
+ tPainting.insert(6, "p_artist3", 101, 1000);
+ tPainting.insert(7, "p_artist21", 11, 2000);
+ tPainting.insert(8, "p_artist22", 11, 3000);
+
+ // flattened join matches an object that is NOT the one we are looking
+ // for
+ tArtistGroup.insert(101, 1);
+
+ // OUTER join part intentionally doesn't match anything
+ Expression exp = new Property<String>("groupArray+.name").eq("XX").orExp(Artist.ARTIST_NAME.eq("artist2"));
+
+ SelectQuery<Artist> q = new SelectQuery<Artist>(Artist.class, exp);
+ q.addPrefetch(Artist.PAINTING_ARRAY.disjoint());
+
+ final List<Artist> results = context.select(q);
+
+ queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
+
+ public void execute() {
+ assertEquals(1, results.size());
+
+ Artist a = results.get(0);
+ assertEquals("artist2", a.getArtistName());
+ assertEquals(2, a.getPaintingArray().size());
+ }
+ });
+ }
+
+ public void testPrefetch9() throws Exception {
+ createTwoArtistsAndTwoPaintingsDataSet();
+
+ Expression artistExp = ExpressionFactory.matchExp("artistName", "artist3");
+ SelectQuery artistQuery = new SelectQuery(Artist.class, artistExp);
+ Artist artist1 = (Artist) context.performQuery(artistQuery).get(0);
+
+ // find the painting not matching the artist (this is the case where
+ // such prefetch
+ // at least makes sense)
+ Expression exp = ExpressionFactory.noMatchExp("toArtist", artist1);
+
+ SelectQuery q = new SelectQuery(Painting.class, exp);
+ q.addPrefetch("toArtist");
+
+ final List<Painting> results = context.performQuery(q);
+
+ queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
+
+ public void execute() {
+ assertEquals(1, results.size());
+
+ // see that artists are resolved...
+
+ Painting px = results.get(0);
+ Artist ax = (Artist) px.readProperty(Painting.TO_ARTIST_PROPERTY);
+ assertEquals(PersistenceState.COMMITTED, ax.getPersistenceState());
+ }
+ });
+ }
+
+ public void testPrefetch_OneToOneWithQualifier() throws Exception {
+ createArtistWithTwoPaintingsAndTwoInfosDataSet();
+
+ Expression e = ExpressionFactory.likeExp("toArtist.artistName", "a%");
+ SelectQuery q = new SelectQuery(Painting.class, e);
+ q.addPrefetch(Painting.TO_PAINTING_INFO_PROPERTY);
+ q.addOrdering(Painting.PAINTING_TITLE_PROPERTY, SortOrder.ASCENDING);
+
+ final List<Painting> results = context.performQuery(q);
+
+ queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
+
+ public void execute() {
+ assertEquals(2, results.size());
+
+ // testing non-null to-one target
+ Painting p0 = results.get(0);
+ Object o2 = p0.readPropertyDirectly(Painting.TO_PAINTING_INFO_PROPERTY);
+ assertTrue(o2 instanceof PaintingInfo);
+ PaintingInfo pi2 = (PaintingInfo) o2;
+ assertEquals(PersistenceState.COMMITTED, pi2.getPersistenceState());
+ assertEquals(Cayenne.intPKForObject(p0), Cayenne.intPKForObject(pi2));
+
+ // testing null to-one target
+ Painting p1 = results.get(1);
+ assertNull(p1.readPropertyDirectly(Painting.TO_PAINTING_INFO_PROPERTY));
+
+ // there was a bug marking an object as dirty when clearing the
+ // relationships
+ assertEquals(PersistenceState.COMMITTED, p1.getPersistenceState());
+ }
+ });
+ }
+
+ public void testPrefetchToMany_DateInQualifier() throws Exception {
+ createTwoArtistsAndTwoPaintingsDataSet();
+
+ Expression e = ExpressionFactory.matchExp("dateOfBirth", new Date());
+ SelectQuery q = new SelectQuery(Artist.class, e);
+ q.addPrefetch("paintingArray");
+
+ // prefetch with query using date in qualifier used to fail on SQL
+ // Server
+ // see CAY-119 for details
+ context.performQuery(q);
+ }
+
+ public void testPrefetchingToOneNull() throws Exception {
+
+ tPainting.insert(6, "p_Xty", null, 1000);
+
+ SelectQuery q = new SelectQuery(Painting.class);
+ q.addPrefetch(Painting.TO_ARTIST_PROPERTY);
+
+ final List<Painting> paintings = context.performQuery(q);
+
+ queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
+
+ public void execute() {
+ assertEquals(1, paintings.size());
+
+ Painting p2 = paintings.get(0);
+ assertNull(p2.readProperty(Painting.TO_ARTIST_PROPERTY));
+ }
+ });
+ }
+
+ public void testPrefetchToOneSharedCache() throws Exception {
+ createTwoArtistsAndTwoPaintingsDataSet();
+
+ final SelectQuery q = new SelectQuery(Painting.class);
+ q.addPrefetch(Painting.TO_ARTIST_PROPERTY);
+ q.setCacheStrategy(QueryCacheStrategy.SHARED_CACHE);
+
+ context.performQuery(q);
+
+ queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
+
+ public void execute() {
+ // per CAY-499 second run of a cached query with prefetches
+ // (i.e. when the
+ // result is served from cache) used to throw an exception...
+
+ List<Painting> cachedResult = context.performQuery(q);
+
+ assertFalse(cachedResult.isEmpty());
+ Painting p1 = cachedResult.get(0);
+
+ Object toOnePrefetch = p1.readNestedProperty("toArtist");
+ assertNotNull(toOnePrefetch);
+ assertTrue("Expected Artist, got: " + toOnePrefetch.getClass().getName(),
+ toOnePrefetch instanceof Artist);
+
+ Artist a1 = (Artist) toOnePrefetch;
+ assertEquals(PersistenceState.COMMITTED, a1.getPersistenceState());
+
+ // and just in case - run one more time...
+ context.performQuery(q);
+ }
+ });
+ }
+
+ public void testPrefetchToOneLocalCache() throws Exception {
+ createTwoArtistsAndTwoPaintingsDataSet();
+
+ final SelectQuery q = new SelectQuery(Painting.class);
+ q.addPrefetch(Painting.TO_ARTIST_PROPERTY);
+ q.setCacheStrategy(QueryCacheStrategy.LOCAL_CACHE);
+
+ context.performQuery(q);
+
+ queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
+
+ public void execute() {
+ // per CAY-499 second run of a cached query with prefetches
+ // (i.e. when the
+ // result is served from cache) used to throw an exception...
+
+ List<Painting> cachedResult = context.performQuery(q);
+
+ assertFalse(cachedResult.isEmpty());
+ Painting p1 = cachedResult.get(0);
+
+ Object toOnePrefetch = p1.readNestedProperty("toArtist");
+ assertNotNull(toOnePrefetch);
+ assertTrue("Expected Artist, got: " + toOnePrefetch.getClass().getName(),
+ toOnePrefetch instanceof Artist);
+
+ Artist a1 = (Artist) toOnePrefetch;
+ assertEquals(PersistenceState.COMMITTED, a1.getPersistenceState());
+
+ // and just in case - run one more time...
+ context.performQuery(q);
+ }
+ });
+ }
+
+ public void testPrefetchToOneWithBackRelationship() 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.disjoint());
+ query.addPrefetch(Painting.TO_PAINTING_INFO.dot(PaintingInfo.PAINTING).disjoint());
+ 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()));
+ }
+ });
+ }
+
+ 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()));
+ }
+ });
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/e42c376c/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextPrefetchMultistepIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextPrefetchMultistepIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextPrefetchMultistepIT.java
new file mode 100644
index 0000000..7adfbbf
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextPrefetchMultistepIT.java
@@ -0,0 +1,311 @@
+/*****************************************************************
+ * 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.Fault;
+import org.apache.cayenne.ObjectId;
+import org.apache.cayenne.PersistenceState;
+import org.apache.cayenne.Persistent;
+import org.apache.cayenne.ValueHolder;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.query.PrefetchTreeNode;
+import org.apache.cayenne.query.SelectQuery;
+import org.apache.cayenne.test.jdbc.DBHelper;
+import org.apache.cayenne.test.jdbc.TableHelper;
+import org.apache.cayenne.testdo.testmap.ArtistExhibit;
+import org.apache.cayenne.testdo.testmap.Exhibit;
+import org.apache.cayenne.testdo.testmap.Gallery;
+import org.apache.cayenne.testdo.testmap.Painting;
+import org.apache.cayenne.unit.di.server.ServerCase;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+
+import java.sql.Timestamp;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@UseServerRuntime(ServerCase.TESTMAP_PROJECT)
+public class DataContextPrefetchMultistepIT extends ServerCase {
+
+ @Inject
+ protected DataContext context;
+
+ @Inject
+ protected DBHelper dbHelper;
+
+ protected TableHelper tArtist;
+ protected TableHelper tExhibit;
+ protected TableHelper tGallery;
+ protected TableHelper tArtistExhibit;
+
+ @Override
+ protected void setUpAfterInjection() throws Exception {
+ dbHelper.deleteAll("PAINTING_INFO");
+ dbHelper.deleteAll("PAINTING");
+ dbHelper.deleteAll("ARTIST_EXHIBIT");
+ dbHelper.deleteAll("ARTIST_GROUP");
+ dbHelper.deleteAll("ARTIST");
+ dbHelper.deleteAll("EXHIBIT");
+ dbHelper.deleteAll("GALLERY");
+
+ tArtist = new TableHelper(dbHelper, "ARTIST");
+ tArtist.setColumns("ARTIST_ID", "ARTIST_NAME");
+
+ tExhibit = new TableHelper(dbHelper, "EXHIBIT");
+ tExhibit.setColumns("EXHIBIT_ID", "GALLERY_ID", "OPENING_DATE", "CLOSING_DATE");
+
+ tArtistExhibit = new TableHelper(dbHelper, "ARTIST_EXHIBIT");
+ tArtistExhibit.setColumns("ARTIST_ID", "EXHIBIT_ID");
+
+ tGallery = new TableHelper(dbHelper, "GALLERY");
+ tGallery.setColumns("GALLERY_ID", "GALLERY_NAME");
+ }
+
+ protected void createTwoArtistsWithExhibitsDataSet() throws Exception {
+ tArtist.insert(11, "artist2");
+ tArtist.insert(101, "artist3");
+
+ tGallery.insert(25, "gallery1");
+ tGallery.insert(31, "gallery2");
+ tGallery.insert(45, "gallery3");
+
+ Timestamp now = new Timestamp(System.currentTimeMillis());
+
+ tExhibit.insert(1, 25, now, now);
+ tExhibit.insert(2, 31, now, now);
+ tExhibit.insert(3, 45, now, now);
+ tExhibit.insert(4, 25, now, now);
+
+ tArtistExhibit.insert(11, 2);
+ tArtistExhibit.insert(11, 4);
+ tArtistExhibit.insert(101, 1);
+ tArtistExhibit.insert(101, 2);
+ tArtistExhibit.insert(101, 4);
+ }
+
+ protected void createGalleriesAndArtists() throws Exception {
+ tArtist.insert(11, "artist2");
+ tArtist.insert(101, "artist3");
+
+ tGallery.insert(25, "gallery1");
+ tGallery.insert(31, "gallery2");
+ tGallery.insert(45, "gallery3");
+ }
+
+ public void testToManyToManyFirstStepUnresolved() throws Exception {
+
+ createTwoArtistsWithExhibitsDataSet();
+
+ // since objects for the phantom prefetches are not retained explicitly, they may
+ // get garbage collected, and we won't be able to detect them
+ // so ensure ObjectStore uses a regular map just for this test
+
+ context.getObjectStore().objectMap = new HashMap<Object, Persistent>();
+
+ // Check the target ArtistExhibit objects do not exist yet
+
+ Map<String, Object> id1 = new HashMap<String, Object>();
+ id1.put("ARTIST_ID", 11);
+ id1.put("EXHIBIT_ID", 2);
+ ObjectId oid1 = new ObjectId("ArtistExhibit", id1);
+
+ Map<String, Object> id2 = new HashMap<String, Object>();
+ id2.put("ARTIST_ID", 101);
+ id2.put("EXHIBIT_ID", 2);
+ ObjectId oid2 = new ObjectId("ArtistExhibit", id2);
+
+ assertNull(context.getGraphManager().getNode(oid1));
+ assertNull(context.getGraphManager().getNode(oid2));
+
+ Expression e = Expression.fromString("galleryName = $name");
+ SelectQuery<Gallery> q = SelectQuery.query(Gallery.class, e.expWithParameters(Collections
+ .singletonMap("name", "gallery2")));
+ q.addPrefetch("exhibitArray.artistExhibitArray");
+
+ List<Gallery> galleries = context.select(q);
+ assertEquals(1, galleries.size());
+
+ Gallery g2 = galleries.get(0);
+
+ // this relationship wasn't explicitly prefetched....
+ Object list = g2.readPropertyDirectly("exhibitArray");
+ assertTrue(list instanceof Fault);
+
+ // however the target objects must be resolved
+ ArtistExhibit ae1 = (ArtistExhibit) context.getGraphManager().getNode(oid1);
+ ArtistExhibit ae2 = (ArtistExhibit) context.getGraphManager().getNode(oid2);
+
+ assertNotNull(ae1);
+ assertNotNull(ae2);
+ assertEquals(PersistenceState.COMMITTED, ae1.getPersistenceState());
+ assertEquals(PersistenceState.COMMITTED, ae2.getPersistenceState());
+ }
+
+ public void testToManyToManyFirstStepResolved() throws Exception {
+
+ createTwoArtistsWithExhibitsDataSet();
+
+ Expression e = Expression.fromString("galleryName = $name");
+ SelectQuery<Gallery> q = SelectQuery.query(Gallery.class, e.expWithParameters(Collections
+ .singletonMap("name", "gallery2")));
+ q.addPrefetch("exhibitArray");
+ q.addPrefetch("exhibitArray.artistExhibitArray");
+
+ List<Gallery> galleries = context.select(q);
+ assertEquals(1, galleries.size());
+
+ Gallery g2 = galleries.get(0);
+
+ // this relationship should be resolved
+ assertTrue(g2.readPropertyDirectly("exhibitArray") instanceof ValueHolder);
+ List<Exhibit> exhibits = (List<Exhibit>) g2.readPropertyDirectly("exhibitArray");
+ assertFalse(((ValueHolder) exhibits).isFault());
+ assertEquals(1, exhibits.size());
+
+ Exhibit e1 = exhibits.get(0);
+ assertEquals(PersistenceState.COMMITTED, e1.getPersistenceState());
+
+ // this to-many must also be resolved
+ assertTrue(e1.readPropertyDirectly("artistExhibitArray") instanceof ValueHolder);
+ List<ArtistExhibit> aexhibits = (List<ArtistExhibit>) e1
+ .readPropertyDirectly("artistExhibitArray");
+ assertFalse(((ValueHolder) aexhibits).isFault());
+ assertEquals(1, exhibits.size());
+
+ ArtistExhibit ae1 = aexhibits.get(0);
+ assertEquals(PersistenceState.COMMITTED, ae1.getPersistenceState());
+ }
+
+ public void testMixedPrefetch1() throws Exception {
+
+ createTwoArtistsWithExhibitsDataSet();
+
+ Expression e = Expression.fromString("galleryName = $name");
+ SelectQuery<Gallery> q = SelectQuery.query(Gallery.class, e.expWithParameters(Collections
+ .singletonMap("name", "gallery2")));
+ q.addPrefetch("exhibitArray").setSemantics(
+ PrefetchTreeNode.JOINT_PREFETCH_SEMANTICS);
+ q.addPrefetch("exhibitArray.artistExhibitArray");
+
+ List<Gallery> galleries = context.select(q);
+ assertEquals(1, galleries.size());
+
+ Gallery g2 = galleries.get(0);
+
+ // this relationship should be resolved
+ assertTrue(g2.readPropertyDirectly("exhibitArray") instanceof ValueHolder);
+ List<Exhibit> exhibits = (List<Exhibit>) g2.readPropertyDirectly("exhibitArray");
+ assertFalse(((ValueHolder) exhibits).isFault());
+ assertEquals(1, exhibits.size());
+
+ Exhibit e1 = exhibits.get(0);
+ assertEquals(PersistenceState.COMMITTED, e1.getPersistenceState());
+
+ // this to-many must also be resolved
+ assertTrue(e1.readPropertyDirectly("artistExhibitArray") instanceof ValueHolder);
+ List<ArtistExhibit> aexhibits = (List<ArtistExhibit>) e1
+ .readPropertyDirectly("artistExhibitArray");
+ assertFalse(((ValueHolder) aexhibits).isFault());
+ assertEquals(2, aexhibits.size());
+
+ ArtistExhibit ae1 = aexhibits.get(0);
+ assertEquals(PersistenceState.COMMITTED, ae1.getPersistenceState());
+ }
+
+ public void testMixedPrefetch2() throws Exception {
+
+ createTwoArtistsWithExhibitsDataSet();
+
+ Expression e = Expression.fromString("galleryName = $name");
+ SelectQuery<Gallery> q = SelectQuery.query(Gallery.class, e.expWithParameters(Collections
+ .singletonMap("name", "gallery2")));
+
+ // reverse the order of prefetches compared to the previous test
+ q.addPrefetch("exhibitArray");
+ q.addPrefetch("exhibitArray.artistExhibitArray").setSemantics(
+ PrefetchTreeNode.JOINT_PREFETCH_SEMANTICS);
+
+ List<Gallery> galleries = context.select(q);
+ assertEquals(1, galleries.size());
+
+ Gallery g2 = galleries.get(0);
+
+ // this relationship should be resolved
+ assertTrue(g2.readPropertyDirectly("exhibitArray") instanceof ValueHolder);
+ List<Exhibit> exhibits = (List<Exhibit>) g2.readPropertyDirectly("exhibitArray");
+ assertFalse(((ValueHolder) exhibits).isFault());
+ assertEquals(1, exhibits.size());
+
+ Exhibit e1 = exhibits.get(0);
+ assertEquals(PersistenceState.COMMITTED, e1.getPersistenceState());
+
+ // this to-many must also be resolved
+ assertTrue(e1.readPropertyDirectly("artistExhibitArray") instanceof ValueHolder);
+ List<ArtistExhibit> aexhibits = (List<ArtistExhibit>) e1
+ .readPropertyDirectly("artistExhibitArray");
+ assertFalse(((ValueHolder) aexhibits).isFault());
+ assertEquals(2, aexhibits.size());
+
+ ArtistExhibit ae1 = aexhibits.get(0);
+ assertEquals(PersistenceState.COMMITTED, ae1.getPersistenceState());
+ }
+
+ public void testToManyToOne_EmptyToMany() throws Exception {
+
+ createGalleriesAndArtists();
+
+ SelectQuery<Gallery> q = SelectQuery.query(Gallery.class, Gallery.GALLERY_NAME.eq("gallery2"));
+ q.addPrefetch(Gallery.PAINTING_ARRAY.disjoint());
+ q.addPrefetch(Gallery.PAINTING_ARRAY.dot(Painting.TO_ARTIST).disjoint());
+
+ List<Gallery> galleries = context.select(q);
+ assertEquals(1, galleries.size());
+
+ Gallery g2 = galleries.get(0);
+
+ // this relationship should be resolved
+ assertTrue(g2.readPropertyDirectly(Gallery.PAINTING_ARRAY.getName()) instanceof ValueHolder);
+ List<Painting> exhibits = (List<Painting>) g2.readPropertyDirectly(Gallery.PAINTING_ARRAY.getName());
+ assertFalse(((ValueHolder) exhibits).isFault());
+ assertEquals(0, exhibits.size());
+ }
+
+ public void testToManyToOne_EmptyToMany_NoRootQualifier() throws Exception {
+
+ createGalleriesAndArtists();
+
+ SelectQuery<Gallery> q = SelectQuery.query(Gallery.class);
+ q.addPrefetch(Gallery.PAINTING_ARRAY.disjoint());
+ q.addPrefetch(Gallery.PAINTING_ARRAY.dot(Painting.TO_ARTIST).disjoint());
+
+ List<Gallery> galleries = context.select(q);
+ assertEquals(3, galleries.size());
+
+ Gallery g = galleries.get(0);
+
+ // this relationship should be resolved
+ assertTrue(g.readPropertyDirectly(Gallery.PAINTING_ARRAY.getName()) instanceof ValueHolder);
+ List<Painting> exhibits = (List<Painting>) g.readPropertyDirectly(Gallery.PAINTING_ARRAY.getName());
+ assertFalse(((ValueHolder) exhibits).isFault());
+ assertEquals(0, exhibits.size());
+ }
+}