use of org.apache.cayenne.map.DbRelationship in project cayenne by apache.
the class EJBQLIdentifierColumnsTranslator method addPrefetchedColumnsIfAny.
private void addPrefetchedColumnsIfAny(final String visitedIdentifier) {
PrefetchTreeNode prefetchTree = context.getCompiledExpression().getPrefetchTree();
if (prefetchTree != null) {
for (PrefetchTreeNode prefetch : prefetchTree.adjacentJointNodes()) {
ClassDescriptor descriptor = context.getEntityDescriptor(prefetch.getEjbqlPathEntityId());
if (visitedIdentifier.equals(prefetch.getEjbqlPathEntityId())) {
DbEntity table = descriptor.getRootDbEntities().iterator().next();
ObjEntity objectEntity = descriptor.getEntity();
prefetch.setEntityName(objectEntity.getName());
Expression prefetchExp = ExpressionFactory.exp(prefetch.getPath());
Expression dbPrefetch = objectEntity.translateToDbPath(prefetchExp);
DbRelationship r = null;
for (PathComponent<DbAttribute, DbRelationship> component : table.resolvePath(dbPrefetch, context.getMetadata().getPathSplitAliases())) {
r = component.getRelationship();
}
if (r == null) {
throw new CayenneRuntimeException("Invalid joint prefetch '%s' for entity: %s", prefetch, objectEntity.getName());
}
for (DbAttribute attribute : r.getTargetEntity().getAttributes()) {
appendColumn(prefetch.getEjbqlPathEntityId() + "." + prefetch.getPath(), attribute, "", prefetch.getPath() + "." + attribute.getName(), null);
}
}
}
}
}
use of org.apache.cayenne.map.DbRelationship in project cayenne by apache.
the class EJBQLIdentifierColumnsTranslator method visitIdentifier.
@Override
public boolean visitIdentifier(EJBQLExpression expression) {
Map<String, String> xfields = null;
if (context.isAppendingResultColumns()) {
xfields = context.nextEntityResult().getFields();
}
// assign whatever we have to a final ivar so that it can be accessed
// within
// the inner class
final Map<String, String> fields = xfields;
final String idVar = expression.getText();
// append all table columns ... the trick is to follow the algorithm for
// describing the fields in the expression compiler, so that we could
// assign
// columns labels from FieldResults in the order we encounter them
// here...
// TODO: andrus 2008/02/17 - this is a bit of a hack, think of a better
// solution
ClassDescriptor descriptor = context.getEntityDescriptor(idVar);
PropertyVisitor visitor = new PropertyVisitor() {
public boolean visitAttribute(AttributeProperty property) {
ObjAttribute oa = property.getAttribute();
Iterator<?> dbPathIterator = oa.getDbPathIterator();
EJBQLJoinAppender joinAppender = null;
String marker = null;
EJBQLTableId lhsId = new EJBQLTableId(idVar);
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) {
if (marker == null) {
marker = EJBQLJoinAppender.makeJoinTailMarker(idVar);
joinAppender = context.getTranslatorFactory().getJoinAppender(context);
}
DbRelationship dr = (DbRelationship) pathPart;
EJBQLTableId rhsId = new EJBQLTableId(lhsId, dr.getName());
joinAppender.appendOuterJoin(marker, lhsId, rhsId);
lhsId = rhsId;
} else if (pathPart instanceof DbAttribute) {
appendColumn(idVar, oa, (DbAttribute) pathPart, fields, oa.getType());
}
}
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) {
ObjRelationship rel = property.getRelationship();
DbRelationship dbRel = rel.getDbRelationships().get(0);
for (DbJoin join : dbRel.getJoins()) {
DbAttribute src = join.getSource();
appendColumn(idVar, null, src, fields);
}
}
};
// EJBQL queries are polymorphic by definition - there is no distinction
// between
// inheritance/no-inheritance fetch
descriptor.visitAllProperties(visitor);
// append id columns ... (some may have been appended already via
// relationships)
DbEntity table = descriptor.getEntity().getDbEntity();
for (DbAttribute pk : table.getPrimaryKeys()) {
appendColumn(idVar, null, pk, fields);
}
// append inheritance discriminator columns...
for (ObjAttribute column : descriptor.getDiscriminatorColumns()) {
appendColumn(idVar, column, column.getDbAttribute(), fields);
}
addPrefetchedColumnsIfAny(idVar);
return false;
}
use of org.apache.cayenne.map.DbRelationship in project cayenne by apache.
the class EJBQLJoinAppender method generateJoinsForFlattenedAttributes.
/**
* Generates Joins statements for those flattened attributes that appear after the
* FROM clause, e.g. in WHERE, ORDER BY, etc clauses. Flattened attributes of the
* entity from the SELECT clause are processed earlier and therefore are omitted.
*
* @param id table to JOIN id
*/
private void generateJoinsForFlattenedAttributes(EJBQLTableId id) {
String entityName = context.getEntityDescriptor(id.getEntityId()).getEntity().getName();
// if the dbPath is not null, all attributes of the entity are processed earlier
boolean isProcessingOmitted = id.getDbPath() != null;
String sourceExpression = context.getCompiledExpression().getSource();
List<Object> resultSetMapping = context.getMetadata().getResultSetMapping();
for (Object mapping : resultSetMapping) {
if (mapping instanceof EntityResultSegment) {
if (entityName.equals(((EntityResultSegment) mapping).getClassDescriptor().getEntity().getName())) {
// if entity is included into SELECT clause, all its attributes are processed earlier
isProcessingOmitted = true;
break;
}
}
}
if (!isProcessingOmitted) {
QuotingStrategy quoter = context.getQuotingStrategy();
Collection<ObjAttribute> attributes = context.getEntityDescriptor(id.getEntityId()).getEntity().getAttributes();
for (ObjAttribute objAttribute : attributes) {
if (objAttribute.isFlattened() && sourceExpression.contains(id.getEntityId() + "." + objAttribute.getName())) {
// joins for attribute are generated if it is flattened and appears in original statement
Iterator<CayenneMapEntry> dbPathIterator = objAttribute.getDbPathIterator();
while (dbPathIterator.hasNext()) {
CayenneMapEntry next = dbPathIterator.next();
if (next instanceof DbRelationship) {
DbRelationship rel = (DbRelationship) next;
context.append(" LEFT OUTER JOIN ");
String targetEntityName = quoter.quotedFullyQualifiedName(rel.getTargetEntity());
String subqueryTargetAlias = context.getTableAlias(id.getEntityId(), targetEntityName);
context.append(targetEntityName).append(' ').append(subqueryTargetAlias);
generateJoiningExpression(rel, context.getTableAlias(id.getEntityId(), quoter.quotedFullyQualifiedName(rel.getSourceEntity())), subqueryTargetAlias);
}
}
}
}
}
}
use of org.apache.cayenne.map.DbRelationship in project cayenne by apache.
the class EJBQLPathTranslator method processTerminatingRelationship.
protected void processTerminatingRelationship(ObjRelationship relationship) {
if (relationship.isSourceIndependentFromTargetChange()) {
// (andrus) use an outer join for to-many matches.. This is somewhat
// different
// from traditional Cayenne SelectQuery, as EJBQL spec does not
// allow regular
// path matches done against to-many relationships, and instead
// provides
// MEMBER OF and IS EMPTY operators. Outer join is needed for IS
// EMPTY... I
// guess MEMBER OF could've been done with an inner join though..
this.innerJoin = false;
resolveJoin();
DbRelationship dbRelationship = chooseDbRelationship(relationship);
DbEntity table = (DbEntity) dbRelationship.getTargetEntity();
String alias = this.lastAlias != null ? lastAlias : context.getTableAlias(idPath, context.getQuotingStrategy().quotedFullyQualifiedName(table));
Collection<DbAttribute> pks = table.getPrimaryKeys();
if (pks.size() == 1) {
DbAttribute pk = pks.iterator().next();
context.append(' ');
if (isUsingAliases()) {
context.append(alias).append('.');
}
context.append(context.getQuotingStrategy().quotedName(pk));
} else {
throw new EJBQLException("Multi-column PK to-many matches are not yet supported.");
}
} else {
// match FK against the target object
DbRelationship dbRelationship = chooseDbRelationship(relationship);
DbEntity table = (DbEntity) dbRelationship.getSourceEntity();
String alias = this.lastAlias != null ? lastAlias : context.getTableAlias(idPath, context.getQuotingStrategy().quotedFullyQualifiedName(table));
List<DbJoin> joins = dbRelationship.getJoins();
if (joins.size() == 1) {
DbJoin join = joins.get(0);
context.append(' ');
if (isUsingAliases()) {
context.append(alias).append('.');
}
context.append(context.getQuotingStrategy().quotedName(join.getSource()));
} else {
Map<String, String> multiColumnMatch = new HashMap<>(joins.size() + 2);
for (DbJoin join : joins) {
String column = isUsingAliases() ? alias + "." + join.getSourceName() : join.getSourceName();
multiColumnMatch.put(join.getTargetName(), column);
}
appendMultiColumnPath(EJBQLMultiColumnOperand.getPathOperand(context, multiColumnMatch));
}
}
}
use of org.apache.cayenne.map.DbRelationship in project cayenne by apache.
the class EJBQLTableId method getDbEntity.
/**
* Returns a DbEntity corresponding to the ID, that could be a root entity for the id,
* or a joined entity.
*/
DbEntity getDbEntity(EJBQLTranslationContext context) {
ClassDescriptor descriptor = context.getEntityDescriptor(entityId);
DbEntity rootEntity = descriptor.getEntity().getDbEntity();
if (dbPath == null) {
return rootEntity;
}
DbRelationship r = null;
Iterator<?> it = rootEntity.resolvePathComponents(dbPath);
while (it.hasNext()) {
r = (DbRelationship) it.next();
}
return (DbEntity) r.getTargetEntity();
}
Aggregations