Search in sources :

Example 11 with DbRelationship

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);
                }
            }
        }
    }
}
Also used : ObjEntity(org.apache.cayenne.map.ObjEntity) ClassDescriptor(org.apache.cayenne.reflect.ClassDescriptor) DbEntity(org.apache.cayenne.map.DbEntity) EJBQLExpression(org.apache.cayenne.ejbql.EJBQLExpression) Expression(org.apache.cayenne.exp.Expression) PrefetchTreeNode(org.apache.cayenne.query.PrefetchTreeNode) DbRelationship(org.apache.cayenne.map.DbRelationship) DbAttribute(org.apache.cayenne.map.DbAttribute) CayenneRuntimeException(org.apache.cayenne.CayenneRuntimeException)

Example 12 with DbRelationship

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;
}
Also used : ObjRelationship(org.apache.cayenne.map.ObjRelationship) ArcProperty(org.apache.cayenne.reflect.ArcProperty) ClassDescriptor(org.apache.cayenne.reflect.ClassDescriptor) ObjAttribute(org.apache.cayenne.map.ObjAttribute) CayenneRuntimeException(org.apache.cayenne.CayenneRuntimeException) DbAttribute(org.apache.cayenne.map.DbAttribute) AttributeProperty(org.apache.cayenne.reflect.AttributeProperty) ToOneProperty(org.apache.cayenne.reflect.ToOneProperty) ToManyProperty(org.apache.cayenne.reflect.ToManyProperty) DbEntity(org.apache.cayenne.map.DbEntity) DbRelationship(org.apache.cayenne.map.DbRelationship) DbJoin(org.apache.cayenne.map.DbJoin) PropertyVisitor(org.apache.cayenne.reflect.PropertyVisitor)

Example 13 with DbRelationship

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);
                    }
                }
            }
        }
    }
}
Also used : CayenneMapEntry(org.apache.cayenne.util.CayenneMapEntry) ObjAttribute(org.apache.cayenne.map.ObjAttribute) DbRelationship(org.apache.cayenne.map.DbRelationship) EntityResultSegment(org.apache.cayenne.query.EntityResultSegment) QuotingStrategy(org.apache.cayenne.dba.QuotingStrategy)

Example 14 with DbRelationship

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));
        }
    }
}
Also used : DbEntity(org.apache.cayenne.map.DbEntity) HashMap(java.util.HashMap) DbRelationship(org.apache.cayenne.map.DbRelationship) DbAttribute(org.apache.cayenne.map.DbAttribute) EJBQLException(org.apache.cayenne.ejbql.EJBQLException) DbJoin(org.apache.cayenne.map.DbJoin)

Example 15 with DbRelationship

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();
}
Also used : ClassDescriptor(org.apache.cayenne.reflect.ClassDescriptor) DbEntity(org.apache.cayenne.map.DbEntity) DbRelationship(org.apache.cayenne.map.DbRelationship)

Aggregations

DbRelationship (org.apache.cayenne.map.DbRelationship)106 DbEntity (org.apache.cayenne.map.DbEntity)59 DbAttribute (org.apache.cayenne.map.DbAttribute)35 DbJoin (org.apache.cayenne.map.DbJoin)35 ObjEntity (org.apache.cayenne.map.ObjEntity)30 ObjRelationship (org.apache.cayenne.map.ObjRelationship)28 ObjAttribute (org.apache.cayenne.map.ObjAttribute)20 Test (org.junit.Test)15 ClassDescriptor (org.apache.cayenne.reflect.ClassDescriptor)13 ArrayList (java.util.ArrayList)11 CayenneRuntimeException (org.apache.cayenne.CayenneRuntimeException)10 EJBQLException (org.apache.cayenne.ejbql.EJBQLException)9 DataMap (org.apache.cayenne.map.DataMap)9 Entity (org.apache.cayenne.map.Entity)8 AttributeProperty (org.apache.cayenne.reflect.AttributeProperty)8 PropertyVisitor (org.apache.cayenne.reflect.PropertyVisitor)8 ToManyProperty (org.apache.cayenne.reflect.ToManyProperty)8 ToOneProperty (org.apache.cayenne.reflect.ToOneProperty)8 HashMap (java.util.HashMap)6 ObjectId (org.apache.cayenne.ObjectId)6