Search in sources :

Example 6 with DbJoin

use of org.apache.cayenne.map.DbJoin in project cayenne by apache.

the class EJBQLDbPathTranslator method processTerminatingRelationship.

protected void processTerminatingRelationship(DbRelationship relationship) {
    if (relationship.isToMany()) {
        // use an outer join for to-many matches
        resolveJoin(false);
        DbEntity table = (DbEntity) relationship.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
        DbEntity table = (DbEntity) relationship.getSourceEntity();
        String alias = this.lastAlias != null ? lastAlias : context.getTableAlias(idPath, context.getQuotingStrategy().quotedFullyQualifiedName(table));
        List<DbJoin> joins = relationship.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) DbAttribute(org.apache.cayenne.map.DbAttribute) EJBQLException(org.apache.cayenne.ejbql.EJBQLException) DbJoin(org.apache.cayenne.map.DbJoin)

Example 7 with DbJoin

use of org.apache.cayenne.map.DbJoin 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 8 with DbJoin

use of org.apache.cayenne.map.DbJoin 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 9 with DbJoin

use of org.apache.cayenne.map.DbJoin in project cayenne by apache.

the class DropColumnToModelIT method testRemoveFKColumnWithoutRelationshipInDb.

@Test
public void testRemoveFKColumnWithoutRelationshipInDb() throws Exception {
    dropTableIfPresent("NEW_TABLE");
    dropTableIfPresent("NEW_TABLE2");
    assertTokensAndExecute(0, 0);
    DbEntity dbEntity1 = new DbEntity("NEW_TABLE");
    DbAttribute e1col1 = new DbAttribute("ID", Types.INTEGER, dbEntity1);
    e1col1.setMandatory(true);
    e1col1.setPrimaryKey(true);
    dbEntity1.addAttribute(e1col1);
    DbAttribute e1col2 = new DbAttribute("NAME", Types.VARCHAR, dbEntity1);
    e1col2.setMaxLength(10);
    e1col2.setMandatory(false);
    dbEntity1.addAttribute(e1col2);
    map.addDbEntity(dbEntity1);
    DbEntity dbEntity2 = new DbEntity("NEW_TABLE2");
    DbAttribute e2col1 = new DbAttribute("ID", Types.INTEGER, dbEntity2);
    e2col1.setMandatory(true);
    e2col1.setPrimaryKey(true);
    dbEntity2.addAttribute(e2col1);
    DbAttribute e2col2 = new DbAttribute("FK", Types.INTEGER, dbEntity2);
    dbEntity2.addAttribute(e2col2);
    DbAttribute e2col3 = new DbAttribute("NAME", Types.VARCHAR, dbEntity2);
    e2col3.setMaxLength(10);
    dbEntity2.addAttribute(e2col3);
    map.addDbEntity(dbEntity2);
    assertTokensAndExecute(2, 0);
    assertTokensAndExecute(0, 0);
    // force drop fk column in db
    execute(mergerFactory().createDropColumnToDb(dbEntity2, e2col2));
    // create db relationships, but do not sync them to db
    DbRelationship rel1To2 = new DbRelationship("rel1To2");
    rel1To2.setSourceEntity(dbEntity1);
    rel1To2.setTargetEntityName(dbEntity2);
    rel1To2.setToMany(true);
    rel1To2.addJoin(new DbJoin(rel1To2, e1col1.getName(), e2col2.getName()));
    dbEntity1.addRelationship(rel1To2);
    DbRelationship rel2To1 = new DbRelationship("rel2To1");
    rel2To1.setSourceEntity(dbEntity2);
    rel2To1.setTargetEntityName(dbEntity1);
    rel2To1.setToMany(false);
    rel2To1.addJoin(new DbJoin(rel2To1, e2col2.getName(), e1col1.getName()));
    dbEntity2.addRelationship(rel2To1);
    assertSame(rel1To2, rel2To1.getReverseRelationship());
    assertSame(rel2To1, rel1To2.getReverseRelationship());
    // create ObjEntities
    ObjEntity objEntity1 = new ObjEntity("NewTable");
    objEntity1.setDbEntity(dbEntity1);
    ObjAttribute oatr1 = new ObjAttribute("name");
    oatr1.setDbAttributePath(e1col2.getName());
    oatr1.setType("java.lang.String");
    objEntity1.addAttribute(oatr1);
    map.addObjEntity(objEntity1);
    ObjEntity objEntity2 = new ObjEntity("NewTable2");
    objEntity2.setDbEntity(dbEntity2);
    ObjAttribute o2a1 = new ObjAttribute("name");
    o2a1.setDbAttributePath(e2col3.getName());
    o2a1.setType("java.lang.String");
    objEntity2.addAttribute(o2a1);
    map.addObjEntity(objEntity2);
    // create ObjRelationships
    assertEquals(0, objEntity1.getRelationships().size());
    assertEquals(0, objEntity2.getRelationships().size());
    ObjRelationship objRel1To2 = new ObjRelationship("objRel1To2");
    objRel1To2.addDbRelationship(rel1To2);
    objRel1To2.setSourceEntity(objEntity1);
    objRel1To2.setTargetEntityName(objEntity2);
    objEntity1.addRelationship(objRel1To2);
    ObjRelationship objRel2To1 = new ObjRelationship("objRel2To1");
    objRel2To1.addDbRelationship(rel2To1);
    objRel2To1.setSourceEntity(objEntity2);
    objRel2To1.setTargetEntityName(objEntity1);
    objEntity2.addRelationship(objRel2To1);
    assertEquals(1, objEntity1.getRelationships().size());
    assertEquals(1, objEntity2.getRelationships().size());
    assertSame(objRel1To2, objRel2To1.getReverseRelationship());
    assertSame(objRel2To1, objRel1To2.getReverseRelationship());
    // try do use the merger to remove the column and relationship in the
    // model
    List<MergerToken> tokens = createMergeTokens();
    assertTokens(tokens, 2, 0);
    // TODO: reversing the following two tokens should also reverse the
    // order
    MergerToken token0 = tokens.get(0).createReverse(mergerFactory());
    MergerToken token1 = tokens.get(1).createReverse(mergerFactory());
    if (!(token0 instanceof DropRelationshipToModel && token1 instanceof DropColumnToModel || token1 instanceof DropRelationshipToModel && token0 instanceof DropColumnToModel)) {
        fail();
    }
    // do not execute DropRelationshipToModel, only DropColumnToModel.
    if (token1 instanceof DropColumnToModel) {
        execute(token1);
    } else {
        execute(token0);
    }
    // check after merging
    assertNull(dbEntity2.getAttribute(e2col2.getName()));
    assertEquals(0, dbEntity1.getRelationships().size());
    assertEquals(0, dbEntity2.getRelationships().size());
    assertEquals(0, objEntity1.getRelationships().size());
    assertEquals(0, objEntity2.getRelationships().size());
    // clear up
    dbEntity1.removeRelationship(rel1To2.getName());
    dbEntity2.removeRelationship(rel2To1.getName());
    map.removeObjEntity(objEntity1.getName(), true);
    map.removeDbEntity(dbEntity1.getName(), true);
    map.removeObjEntity(objEntity2.getName(), true);
    map.removeDbEntity(dbEntity2.getName(), true);
    resolver.refreshMappingCache();
    assertNull(map.getObjEntity(objEntity1.getName()));
    assertNull(map.getDbEntity(dbEntity1.getName()));
    assertNull(map.getObjEntity(objEntity2.getName()));
    assertNull(map.getDbEntity(dbEntity2.getName()));
    assertFalse(map.getDbEntities().contains(dbEntity1));
    assertFalse(map.getDbEntities().contains(dbEntity2));
    assertTokensAndExecute(2, 0);
    assertTokensAndExecute(0, 0);
}
Also used : ObjEntity(org.apache.cayenne.map.ObjEntity) ObjRelationship(org.apache.cayenne.map.ObjRelationship) DbEntity(org.apache.cayenne.map.DbEntity) ObjAttribute(org.apache.cayenne.map.ObjAttribute) DbRelationship(org.apache.cayenne.map.DbRelationship) DbAttribute(org.apache.cayenne.map.DbAttribute) MergerToken(org.apache.cayenne.dbsync.merge.token.MergerToken) DbJoin(org.apache.cayenne.map.DbJoin) Test(org.junit.Test)

Example 10 with DbJoin

use of org.apache.cayenne.map.DbJoin in project cayenne by apache.

the class DbRelationshipMerger method createTokensForMissingOriginal.

/**
 * @param imported DbRelationship that is in db but not in model
 * @return generated tokens
 */
@Override
Collection<MergerToken> createTokensForMissingOriginal(DbRelationship imported) {
    DbEntity originalDbEntity = getOriginalSourceDbEntity(imported);
    DbEntity targetEntity = getOriginalTargetDbEntity(imported);
    if (targetEntity != null) {
        imported.setTargetEntityName(targetEntity);
    }
    imported.setSourceEntity(originalDbEntity);
    // manipulate the joins to match the DbAttributes in the model
    for (DbJoin join : imported.getJoins()) {
        DbAttribute sourceAttr = findDbAttribute(originalDbEntity, join.getSourceName());
        if (sourceAttr != null) {
            join.setSourceName(sourceAttr.getName());
        }
        DbAttribute targetAttr = findDbAttribute(targetEntity, join.getTargetName());
        if (targetAttr != null) {
            join.setTargetName(targetAttr.getName());
        }
    }
    // Add all relationships. Tokens will decide whether or not to execute
    MergerToken token = getTokenFactory().createDropRelationshipToDb(originalDbEntity, imported);
    return Collections.singleton(token);
}
Also used : DbEntity(org.apache.cayenne.map.DbEntity) DbAttribute(org.apache.cayenne.map.DbAttribute) MergerToken(org.apache.cayenne.dbsync.merge.token.MergerToken) DbJoin(org.apache.cayenne.map.DbJoin)

Aggregations

DbJoin (org.apache.cayenne.map.DbJoin)49 DbRelationship (org.apache.cayenne.map.DbRelationship)35 DbEntity (org.apache.cayenne.map.DbEntity)24 DbAttribute (org.apache.cayenne.map.DbAttribute)18 ObjRelationship (org.apache.cayenne.map.ObjRelationship)14 ObjAttribute (org.apache.cayenne.map.ObjAttribute)12 ObjEntity (org.apache.cayenne.map.ObjEntity)11 ClassDescriptor (org.apache.cayenne.reflect.ClassDescriptor)9 CayenneRuntimeException (org.apache.cayenne.CayenneRuntimeException)8 ArrayList (java.util.ArrayList)7 AttributeProperty (org.apache.cayenne.reflect.AttributeProperty)7 PropertyVisitor (org.apache.cayenne.reflect.PropertyVisitor)7 ToManyProperty (org.apache.cayenne.reflect.ToManyProperty)7 ToOneProperty (org.apache.cayenne.reflect.ToOneProperty)7 HashMap (java.util.HashMap)6 Test (org.junit.Test)6 QuotingStrategy (org.apache.cayenne.dba.QuotingStrategy)5 EJBQLException (org.apache.cayenne.ejbql.EJBQLException)5 HashSet (java.util.HashSet)4 List (java.util.List)3