use of org.apache.cayenne.map.ObjRelationship in project cayenne by apache.
the class SelectQueryIT method testRouteQueryWithPrefetchesNoReverse.
/**
* Tests that all queries specified in prefetch are executed in a more
* complex prefetch scenario with no reverse obj relationships.
*/
@Test
public void testRouteQueryWithPrefetchesNoReverse() {
EntityResolver resolver = context.getEntityResolver();
ObjEntity paintingEntity = resolver.getObjEntity(Painting.class);
ObjEntity galleryEntity = resolver.getObjEntity(Gallery.class);
ObjEntity artistExhibitEntity = resolver.getObjEntity(ArtistExhibit.class);
ObjEntity exhibitEntity = resolver.getObjEntity(Exhibit.class);
ObjRelationship paintingToArtistRel = paintingEntity.getRelationship("toArtist");
paintingEntity.removeRelationship("toArtist");
ObjRelationship galleryToPaintingRel = galleryEntity.getRelationship("paintingArray");
galleryEntity.removeRelationship("paintingArray");
ObjRelationship artistExhibitToArtistRel = artistExhibitEntity.getRelationship("toArtist");
artistExhibitEntity.removeRelationship("toArtist");
ObjRelationship exhibitToArtistExhibitRel = exhibitEntity.getRelationship("artistExhibitArray");
exhibitEntity.removeRelationship("artistExhibitArray");
Expression e = ExpressionFactory.matchExp("artistName", "artist1");
SelectQuery<Artist> q = new SelectQuery<>(Artist.class, e);
q.addPrefetch("paintingArray");
q.addPrefetch("paintingArray.toGallery");
q.addPrefetch("artistExhibitArray.toExhibit");
try {
MockQueryRouter router = new MockQueryRouter();
q.route(router, resolver, null);
assertEquals(4, router.getQueryCount());
} finally {
paintingEntity.addRelationship(paintingToArtistRel);
galleryEntity.addRelationship(galleryToPaintingRel);
artistExhibitEntity.addRelationship(artistExhibitToArtistRel);
exhibitEntity.addRelationship(exhibitToArtistExhibitRel);
}
}
use of org.apache.cayenne.map.ObjRelationship in project cayenne by apache.
the class DefaultSelectTranslator method appendQueryColumns.
/**
* Appends columns needed for object SelectQuery to the provided columns
* list.
*/
<T> List<ColumnDescriptor> appendQueryColumns(final List<ColumnDescriptor> columns, SelectQuery<T> query, ClassDescriptor descriptor, final String tableAlias) {
final Set<ColumnTracker> attributes = new HashSet<>();
// fetched attributes include attributes that are either:
//
// * class properties
// * PK
// * FK used in relationship
// * joined prefetch PK
ObjEntity oe = descriptor.getEntity();
PropertyVisitor visitor = new PropertyVisitor() {
public boolean visitAttribute(AttributeProperty property) {
ObjAttribute oa = property.getAttribute();
resetJoinStack();
Iterator<CayenneMapEntry> dbPathIterator = oa.getDbPathIterator();
while (dbPathIterator.hasNext()) {
Object pathPart = dbPathIterator.next();
if (pathPart == null) {
throw new CayenneRuntimeException("ObjAttribute has no component: %s", oa.getName());
} else if (pathPart instanceof DbRelationship) {
DbRelationship rel = (DbRelationship) pathPart;
dbRelationshipAdded(rel, JoinType.LEFT_OUTER, null);
} else if (pathPart instanceof DbAttribute) {
DbAttribute dbAttr = (DbAttribute) pathPart;
appendColumn(columns, oa, dbAttr, attributes, null, tableAlias);
}
}
return true;
}
public boolean visitToMany(ToManyProperty property) {
visitRelationship(property);
return true;
}
public boolean visitToOne(ToOneProperty property) {
visitRelationship(property);
return true;
}
private void visitRelationship(ArcProperty property) {
resetJoinStack();
ObjRelationship rel = property.getRelationship();
DbRelationship dbRel = rel.getDbRelationships().get(0);
List<DbJoin> joins = dbRel.getJoins();
for (DbJoin join : joins) {
DbAttribute src = join.getSource();
appendColumn(columns, null, src, attributes, null, tableAlias);
}
}
};
descriptor.visitAllProperties(visitor);
// stack should be reset, because all root table attributes go with "t0"
// table alias
resetJoinStack();
// add remaining needed attrs from DbEntity
DbEntity table = oe.getDbEntity();
for (DbAttribute dba : table.getPrimaryKeys()) {
appendColumn(columns, null, dba, attributes, null, tableAlias);
}
if (query instanceof PrefetchSelectQuery) {
// for each relationship path add PK of the target entity...
for (String path : ((PrefetchSelectQuery) query).getResultPaths()) {
ASTDbPath pathExp = (ASTDbPath) oe.translateToDbPath(ExpressionFactory.exp(path));
// add joins and find terminating element
resetJoinStack();
PathComponent<DbAttribute, DbRelationship> lastComponent = null;
for (PathComponent<DbAttribute, DbRelationship> component : table.resolvePath(pathExp, getPathAliases())) {
if (component.getRelationship() != null) {
// do not invoke dbRelationshipAdded(), invoke
// pushJoin() instead. This is to prevent
// 'forcingDistinct' flipping to true, that will result
// in unneeded extra processing and sometimes in invalid
// results (see CAY-1979). Distinctness of each row is
// guaranteed by the prefetch query semantics - we
// include target ID in the result columns
getJoinStack().pushJoin(component.getRelationship(), component.getJoinType(), null);
}
lastComponent = component;
}
// process terminating element
if (lastComponent != null) {
DbRelationship relationship = lastComponent.getRelationship();
if (relationship != null) {
String labelPrefix = pathExp.getPath();
DbEntity targetEntity = relationship.getTargetEntity();
for (DbAttribute pk : targetEntity.getPrimaryKeys()) {
// note that we my select a source attribute, but
// label it as
// target for simplified snapshot processing
appendColumn(columns, null, pk, attributes, labelPrefix + '.' + pk.getName());
}
}
}
}
}
// handle joint prefetches directly attached to this query...
if (query.getPrefetchTree() != null) {
// perform some sort of union or sub-queries.
for (PrefetchTreeNode prefetch : query.getPrefetchTree().getChildren()) {
prefetch.setEntityName(oe.getName());
}
for (PrefetchTreeNode prefetch : query.getPrefetchTree().adjacentJointNodes()) {
// for each prefetch add all joins plus columns from the target
// entity
Expression prefetchExp = ExpressionFactory.exp(prefetch.getPath());
ASTDbPath dbPrefetch = (ASTDbPath) oe.translateToDbPath(prefetchExp);
resetJoinStack();
DbRelationship r = null;
for (PathComponent<DbAttribute, DbRelationship> component : table.resolvePath(dbPrefetch, getPathAliases())) {
r = component.getRelationship();
dbRelationshipAdded(r, JoinType.LEFT_OUTER, null);
}
if (r == null) {
throw new CayenneRuntimeException("Invalid joint prefetch '%s' for entity: %s", prefetch, oe.getName());
}
// add columns from the target entity, including those that are matched
// against the FK of the source entity.
// This is needed to determine whether optional relationships are null
// go via target OE to make sure that Java types are mapped correctly...
ObjRelationship targetRel = (ObjRelationship) prefetchExp.evaluate(oe);
ObjEntity targetEntity = targetRel.getTargetEntity();
String labelPrefix = dbPrefetch.getPath();
PropertyVisitor prefetchVisitor = new PropertyVisitor() {
public boolean visitAttribute(AttributeProperty property) {
ObjAttribute oa = property.getAttribute();
Iterator<CayenneMapEntry> dbPathIterator = oa.getDbPathIterator();
while (dbPathIterator.hasNext()) {
Object pathPart = dbPathIterator.next();
if (pathPart == null) {
throw new CayenneRuntimeException("ObjAttribute has no component: %s", oa.getName());
} else if (pathPart instanceof DbRelationship) {
DbRelationship rel = (DbRelationship) pathPart;
dbRelationshipAdded(rel, JoinType.INNER, null);
} else if (pathPart instanceof DbAttribute) {
DbAttribute dbAttr = (DbAttribute) pathPart;
appendColumn(columns, oa, dbAttr, attributes, labelPrefix + '.' + dbAttr.getName());
}
}
return true;
}
public boolean visitToMany(ToManyProperty property) {
return true;
}
public boolean visitToOne(ToOneProperty property) {
return true;
}
};
ClassDescriptor prefetchClassDescriptor = entityResolver.getClassDescriptor(targetEntity.getName());
prefetchClassDescriptor.visitAllProperties(prefetchVisitor);
// append remaining target attributes such as keys
DbEntity targetDbEntity = r.getTargetEntity();
for (DbAttribute attribute : targetDbEntity.getAttributes()) {
appendColumn(columns, null, attribute, attributes, labelPrefix + '.' + attribute.getName());
}
}
}
return columns;
}
use of org.apache.cayenne.map.ObjRelationship in project cayenne by apache.
the class ObjRelationshipHandler method addObjRelationship.
private void addObjRelationship(Attributes attributes) throws SAXException {
String name = attributes.getValue("name");
if (null == name) {
throw new SAXException("ObjRelationshipHandler::addObjRelationship() - unable to parse target.");
}
String sourceName = attributes.getValue("source");
if (sourceName == null) {
throw new SAXException("ObjRelationshipHandler::addObjRelationship() - unable to parse source.");
}
ObjEntity source = map.getObjEntity(sourceName);
if (source == null) {
throw new SAXException("ObjRelationshipHandler::addObjRelationship() - unable to find source " + sourceName);
}
objRelationship = new ObjRelationship(name);
objRelationship.setSourceEntity(source);
objRelationship.setTargetEntityName(attributes.getValue("target"));
objRelationship.setDeleteRule(DeleteRule.deleteRuleForName(attributes.getValue("deleteRule")));
objRelationship.setUsedForLocking(DataMapHandler.TRUE.equalsIgnoreCase(attributes.getValue("lock")));
objRelationship.setDeferredDbRelationshipPath((attributes.getValue("db-relationship-path")));
objRelationship.setCollectionType(attributes.getValue("collection-type"));
objRelationship.setMapKey(attributes.getValue("map-key"));
source.addRelationship(objRelationship);
}
use of org.apache.cayenne.map.ObjRelationship in project cayenne by apache.
the class DataContextPrefetchIT method testPrefetch_ToManyNoReverseWithQualifier.
@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);
}
}
use of org.apache.cayenne.map.ObjRelationship in project cayenne by apache.
the class PersistentDescriptorFactory method getDescriptor.
protected ClassDescriptor getDescriptor(ObjEntity entity, Class<?> entityClass) {
String superEntityName = entity.getSuperEntityName();
ClassDescriptor superDescriptor = (superEntityName != null) ? descriptorMap.getDescriptor(superEntityName) : null;
PersistentDescriptor descriptor = createDescriptor();
descriptor.setEntity(entity);
descriptor.setSuperclassDescriptor(superDescriptor);
descriptor.setObjectClass(entityClass);
descriptor.setPersistenceStateAccessor(new BeanAccessor(entityClass, "persistenceState", Integer.TYPE));
// only include this entity attributes and skip superclasses...
for (ObjAttribute attribute : descriptor.getEntity().getDeclaredAttributes()) {
if (attribute instanceof EmbeddedAttribute) {
EmbeddedAttribute embedded = (EmbeddedAttribute) attribute;
for (ObjAttribute objAttribute : embedded.getAttributes()) {
createEmbeddedAttributeProperty(descriptor, embedded, objAttribute);
}
} else {
createAttributeProperty(descriptor, attribute);
}
}
// only include this entity relationships and skip superclasses...
for (ObjRelationship relationship : descriptor.getEntity().getDeclaredRelationships()) {
if (relationship.isToMany()) {
String collectionType = relationship.getCollectionType();
if (collectionType == null || ObjRelationship.DEFAULT_COLLECTION_TYPE.equals(collectionType)) {
createToManyListProperty(descriptor, relationship);
} else if ("java.util.Map".equals(collectionType)) {
createToManyMapProperty(descriptor, relationship);
} else if ("java.util.Set".equals(collectionType)) {
createToManySetProperty(descriptor, relationship);
} else if ("java.util.Collection".equals(collectionType)) {
createToManyCollectionProperty(descriptor, relationship);
} else {
throw new IllegalArgumentException("Unsupported to-many collection type: " + collectionType);
}
} else {
createToOneProperty(descriptor, relationship);
}
}
EntityInheritanceTree inheritanceTree = descriptorMap.getResolver().getInheritanceTree(descriptor.getEntity().getName());
descriptor.setEntityInheritanceTree(inheritanceTree);
indexSubclassDescriptors(descriptor, inheritanceTree);
indexQualifiers(descriptor, inheritanceTree);
appendDeclaredRootDbEntity(descriptor, descriptor.getEntity());
indexRootDbEntities(descriptor, inheritanceTree);
indexSuperclassProperties(descriptor);
descriptor.sortProperties();
return descriptor;
}
Aggregations