/*****************************************************************
* 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.QueryCacheStrategy;
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.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.CayenneProjects;
import org.apache.cayenne.unit.di.server.ServerCase;
import org.apache.cayenne.unit.di.server.UseServerRuntime;
import org.junit.Before;
import org.junit.Test;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.junit.Assert.*;
@UseServerRuntime(CayenneProjects.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;
@Before
public void setUp() throws Exception {
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);
}
@Test
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());
}
}
});
}
@Test
public void testPrefetchToMany_WithQualfier() throws Exception {
createTwoArtistsAndTwoPaintingsDataSet();
Map<String, Object> params = new HashMap<>();
params.put("name1", "artist2");
params.put("name2", "artist3");
Expression e = ExpressionFactory.exp("artistName = $name1 or artistName = $name2");
SelectQuery<Artist> q = new SelectQuery<>("Artist", e.params(params));
q.addPrefetch(Artist.PAINTING_ARRAY.disjoint());
final List<Artist> artists = context.select(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.getName());
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.getName());
assertNotNull(toMany2);
assertFalse(((ValueHolder) toMany2).isFault());
assertEquals(1, toMany2.size());
Painting p2 = (Painting) toMany2.get(0);
assertEquals("p_" + a2.getArtistName(), p2.getPaintingTitle());
}
});
}
@Test
public void testPrefetchToManyNoQualifier() throws Exception {
createTwoArtistsAndTwoPaintingsDataSet();
SelectQuery q = new SelectQuery(Artist.class);
q.addPrefetch(Artist.PAINTING_ARRAY.disjoint());
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.
*/
@Test
public void testPrefetchToMany_OnJoinTableDisjoinedPrefetch() throws Exception {
createTwoArtistsWithExhibitsDataSet();
SelectQuery q = new SelectQuery(Artist.class);
q.addPrefetch(Artist.ARTIST_EXHIBIT_ARRAY.disjoint());
q.addOrdering(Artist.ARTIST_NAME.asc());
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.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
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.
*/
@Test
public void testPrefetchToManyOnJoinTableJoinedPrefetch() throws Exception {
createTwoArtistsWithExhibitsDataSet();
SelectQuery q = new SelectQuery(Artist.class);
q.addPrefetch(Artist.ARTIST_EXHIBIT_ARRAY.joint());
q.addOrdering(Artist.ARTIST_NAME.asc());
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.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 there is no inverse
* relationship
*/
@Test
public void testPrefetch_ToManyNoReverse() throws Exception {
createTwoArtistsAndTwoPaintingsDataSet();
ObjEntity paintingEntity = context.getEntityResolver().getObjEntity(Painting.class);
ObjRelationship relationship = paintingEntity.getRelationship("toArtist");
paintingEntity.removeRelationship("toArtist");
try {
SelectQuery<Artist> q = new SelectQuery<>(Artist.class);
q.addPrefetch(Artist.PAINTING_ARRAY.disjoint());
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);
}
}
@Test
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.disjoint());
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);
}
}
@Test
public void testPrefetch_ToOne() throws Exception {
createTwoArtistsAndTwoPaintingsDataSet();
SelectQuery q = new SelectQuery(Painting.class);
q.addPrefetch(Painting.TO_ARTIST.disjoint());
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());
}
});
}
@Test
public void testPrefetch_ToOne_DbPath() throws Exception {
createTwoArtistsAndTwoPaintingsDataSet();
SelectQuery q = new SelectQuery(Painting.class);
q.addPrefetch(Painting.TO_ARTIST.disjoint());
q.andQualifier(ExpressionFactory.matchDbExp("toArtist.ARTIST_NAME", "artist2"));
List<Painting> results = context.performQuery(q);
assertEquals(1, results.size());
}
@Test
public void testPrefetch_ToOne_ObjPath() throws Exception {
createTwoArtistsAndTwoPaintingsDataSet();
SelectQuery q = new SelectQuery(Painting.class);
q.addPrefetch(Painting.TO_ARTIST.disjoint());
q.andQualifier(ExpressionFactory.matchExp("toArtist.artistName", "artist2"));
List<Painting> results = context.performQuery(q);
assertEquals(1, results.size());
}
@Test
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());
}
});
child.setToParentGroup(null);
context.commitChanges();
}
@Test
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.disjoint());
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());
}
});
}
@Test
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 = Property.create("groupArray+.name", String.class).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());
}
});
}
@Test
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.getName());
assertEquals(PersistenceState.COMMITTED, ax.getPersistenceState());
}
});
}
@Test
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.disjoint());
q.addOrdering(Painting.PAINTING_TITLE.asc());
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.getName());
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.getName()));
// there was a bug marking an object as dirty when clearing the
// relationships
assertEquals(PersistenceState.COMMITTED, p1.getPersistenceState());
}
});
}
@Test
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);
}
@Test
public void testPrefetchingToOneNull() throws Exception {
tPainting.insert(6, "p_Xty", null, 1000);
SelectQuery q = new SelectQuery(Painting.class);
q.addPrefetch(Painting.TO_ARTIST.disjoint());
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.getName()));
}
});
}
@Test
public void testPrefetchToOneSharedCache() throws Exception {
createTwoArtistsAndTwoPaintingsDataSet();
final SelectQuery q = new SelectQuery(Painting.class);
q.addPrefetch(Painting.TO_ARTIST.disjoint());
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);
}
});
}
@Test
public void testPrefetchToOneLocalCache() throws Exception {
createTwoArtistsAndTwoPaintingsDataSet();
final SelectQuery q = new SelectQuery(Painting.class);
q.addPrefetch(Painting.TO_ARTIST.disjoint());
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);
}
});
}
@Test
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()));
}
});
}
@Test
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());
}
});
}
@Test
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()));
}
});
}
@Test
public void testPrefetchJointAndDisjointByIdTogether() throws Exception {
createArtistWithTwoPaintingsAndTwoInfosDataSet();
SelectQuery<Painting> query = new SelectQuery<Painting>(Painting.class);
query.andQualifier(Painting.PAINTING_TITLE.eq("p_artist2"));
query.addPrefetch(Painting.TO_ARTIST.joint());
query.addPrefetch(Painting.TO_PAINTING_INFO.disjointById());
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);
PaintingInfo info = (PaintingInfo) p0.readPropertyDirectly(Painting.TO_PAINTING_INFO.getName());
assertNotNull(info);
}
});
}
}