Iterator<CayenneMapEntry> dbPathIterator = oa.getDbPathIterator();
while (dbPathIterator.hasNext()) {
Object pathPart = dbPathIterator.next();
if (pathPart == null) {
throw new CayenneRuntimeException(
"ObjAttribute has no component: " + 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, null);
}
}
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);
List<DbJoin> joins = dbRel.getJoins();
int len = joins.size();
for (int i = 0; i < len; i++) {
DbJoin join = joins.get(i);
DbAttribute src = join.getSource();
appendColumn(columns, null, src, attributes, null);
}
}
};
if (query.isResolvingInherited()) {
descriptor.visitAllProperties(visitor);
}
else {
descriptor.visitProperties(visitor);
}
// add remaining needed attrs from DbEntity
DbEntity table = getRootDbEntity();
for (final DbAttribute dba : table.getPrimaryKeys()) {
appendColumn(columns, null, dba, attributes, null);
}
// special handling of a disjoint query...
// TODO, Andrus 11/17/2005 - resultPath mechanism is generic and should probably
// be moved in the superclass (SelectQuery), replacing customDbAttributes.
if (query instanceof PrefetchSelectQuery) {
// for each relationship path add closest FK or PK, for each attribute path,
// add specified column
for (String path : ((PrefetchSelectQuery) query).getResultPaths()) {
Expression pathExp = oe.translateToDbPath(Expression.fromString(path));
// add joins and find terminating element
resetJoinStack();
PathComponent<DbAttribute, DbRelationship> lastComponent = null;
for (PathComponent<DbAttribute, DbRelationship> component : table
.resolvePath(pathExp, getPathAliases())) {
// do not add join for the last DB Rel
if (component.getRelationship() != null && !component.isLast()) {
dbRelationshipAdded(component.getRelationship(), component
.getJoinType(), null);
}
lastComponent = component;
}
String labelPrefix = pathExp.toString().substring("db:".length());
// process terminating element
if (lastComponent != null) {
DbRelationship relationship = lastComponent.getRelationship();
if (relationship != null) {
// add last join
if (relationship.isToMany()) {
dbRelationshipAdded(relationship, JoinType.INNER, null);
}
for (DbJoin j : relationship.getJoins()) {
DbAttribute attribute = relationship.isToMany() ? j
.getTarget() : j.getSource();
// note that we my select a source attribute, but label it as
// target for simplified snapshot processing
appendColumn(
columns,
null,
attribute,
attributes,
labelPrefix + '.' + j.getTargetName());
}
}
else {
// label prefix already includes relationship name
appendColumn(
columns,
null,
lastComponent.getAttribute(),
attributes,
labelPrefix);
}
}
}
}
// handle joint prefetches directly attached to this query...
if (query.getPrefetchTree() != null) {
for (PrefetchTreeNode prefetch : query.getPrefetchTree().adjacentJointNodes()) {
// for each prefetch add all joins plus columns from the target entity
Expression prefetchExp = Expression.fromString(prefetch.getPath());
Expression dbPrefetch = oe.translateToDbPath(prefetchExp);
resetJoinStack();
DbRelationship r = null;
for (PathComponent<DbAttribute, DbRelationship> component : table
.resolvePath(dbPrefetch, getPathAliases())) {
r = component.getRelationship();
dbRelationshipAdded(r, JoinType.INNER, null);
}
if (r == null) {
throw new CayenneRuntimeException("Invalid joint prefetch '"
+ prefetch
+ "' for entity: "
+ oe.getName());
}
// add columns from the target entity, skipping those that are an FK to
// source entity
Collection<DbAttribute> skipColumns = Collections.EMPTY_LIST;
if (r.getSourceEntity() == table) {
skipColumns = new ArrayList<DbAttribute>(2);
for (final DbJoin join : r.getJoins()) {
if (attributes.contains(join.getSource())) {
skipColumns.add(join.getTarget());
}
}
}
// go via target OE to make sure that Java types are mapped correctly...
ObjRelationship targetRel = (ObjRelationship) prefetchExp.evaluate(oe);
Iterator<ObjAttribute> targetObjAttrs = (Iterator<ObjAttribute>) targetRel
.getTargetEntity()
.getAttributes()
.iterator();
String labelPrefix = dbPrefetch.toString().substring("db:".length());
while (targetObjAttrs.hasNext()) {
ObjAttribute oa = targetObjAttrs.next();
Iterator<CayenneMapEntry> dbPathIterator = oa.getDbPathIterator();
while (dbPathIterator.hasNext()) {
Object pathPart = dbPathIterator.next();
if (pathPart == null) {
throw new CayenneRuntimeException(
"ObjAttribute has no component: " + oa.getName());
}
else if (pathPart instanceof DbRelationship) {
DbRelationship rel = (DbRelationship) pathPart;