use of org.apache.cayenne.map.DbRelationship in project cayenne by apache.
the class Compiler method compileEntityResult.
private EntityResult compileEntityResult(EJBQLExpression expression, int position) {
String id = expression.getText().toLowerCase();
ClassDescriptor descriptor = descriptorsById.get(id);
if (descriptor == null) {
descriptor = descriptorsById.get(expression.getText());
}
if (descriptor == null) {
throw new EJBQLException("the entity variable '" + id + "' does not refer to any entity in the FROM clause");
}
final EntityResult entityResult = new EntityResult(descriptor.getObjectClass());
final String prefix = "ec" + position + "_";
final int[] index = { 0 };
final Set<String> visited = new HashSet<String>();
PropertyVisitor visitor = new PropertyVisitor() {
public boolean visitAttribute(AttributeProperty property) {
ObjAttribute oa = property.getAttribute();
if (visited.add(oa.getDbAttributePath())) {
entityResult.addObjectField(oa.getEntity().getName(), oa.getName(), prefix + index[0]++);
}
return true;
}
public boolean visitToMany(ToManyProperty property) {
return true;
}
public boolean visitToOne(ToOneProperty property) {
ObjRelationship rel = property.getRelationship();
DbRelationship dbRel = rel.getDbRelationships().get(0);
for (DbJoin join : dbRel.getJoins()) {
DbAttribute src = join.getSource();
if (src.isForeignKey() && visited.add(src.getName())) {
entityResult.addDbField(src.getName(), prefix + index[0]++);
}
}
return true;
}
};
descriptor.visitAllProperties(visitor);
// append id columns ... (some may have been appended already via relationships)
for (String pkName : descriptor.getEntity().getPrimaryKeyNames()) {
if (visited.add(pkName)) {
entityResult.addDbField(pkName, prefix + index[0]++);
}
}
// append inheritance discriminator columns...
for (ObjAttribute column : descriptor.getDiscriminatorColumns()) {
if (visited.add(column.getName())) {
entityResult.addDbField(column.getDbAttributePath(), prefix + index[0]++);
}
}
return entityResult;
}
use of org.apache.cayenne.map.DbRelationship in project cayenne by apache.
the class SelectQueryMetadata method buildEntityResultForColumn.
/**
* Collect metadata for column that will be unwrapped to full entity in the final SQL
* (possibly including joint prefetch).
* This information will be used to correctly create Persistent object back from raw result.
*
* This method is actually repeating logic of
* {@link org.apache.cayenne.access.translator.select.DefaultSelectTranslator#appendQueryColumns}.
* Here we don't care about intermediate joins and few other things so it's shorter.
* Logic of these methods should be unified and simplified, possibly to a single source of metadata,
* generated only once and used everywhere.
*
* @param query original query
* @param column full object column
* @param resolver entity resolver to get ObjEntity and ClassDescriptor
* @return Entity result
*/
private EntityResult buildEntityResultForColumn(SelectQuery<?> query, Property<?> column, EntityResolver resolver) {
final EntityResult result = new EntityResult(column.getType());
// Collecting visitor for ObjAttributes and toOne relationships
PropertyVisitor visitor = new PropertyVisitor() {
public boolean visitAttribute(AttributeProperty property) {
ObjAttribute oa = property.getAttribute();
Iterator<CayenneMapEntry> dbPathIterator = oa.getDbPathIterator();
while (dbPathIterator.hasNext()) {
CayenneMapEntry pathPart = dbPathIterator.next();
if (pathPart instanceof DbAttribute) {
result.addDbField(pathPart.getName(), pathPart.getName());
}
}
return true;
}
public boolean visitToMany(ToManyProperty property) {
return true;
}
public boolean visitToOne(ToOneProperty property) {
DbRelationship dbRel = property.getRelationship().getDbRelationships().get(0);
List<DbJoin> joins = dbRel.getJoins();
for (DbJoin join : joins) {
if (!join.getSource().isPrimaryKey()) {
result.addDbField(join.getSource().getName(), join.getSource().getName());
}
}
return true;
}
};
ObjEntity oe = resolver.getObjEntity(column.getType());
DbEntity table = oe.getDbEntity();
// Additionally collect PKs
for (DbAttribute dba : table.getPrimaryKeys()) {
result.addDbField(dba.getName(), dba.getName());
}
ClassDescriptor descriptor = resolver.getClassDescriptor(oe.getName());
descriptor.visitAllProperties(visitor);
// Collection columns for joint prefetch
if (query.getPrefetchTree() != null) {
for (PrefetchTreeNode prefetch : query.getPrefetchTree().adjacentJointNodes()) {
// for each prefetch add columns from the target entity
Expression prefetchExp = ExpressionFactory.exp(prefetch.getPath());
ASTDbPath dbPrefetch = (ASTDbPath) oe.translateToDbPath(prefetchExp);
DbRelationship r = findRelationByPath(table, dbPrefetch);
if (r == null) {
throw new CayenneRuntimeException("Invalid joint prefetch '%s' for entity: %s", prefetch, oe.getName());
}
// go via target OE to make sure that Java types are mapped correctly...
ObjRelationship targetRel = (ObjRelationship) prefetchExp.evaluate(oe);
ObjEntity targetEntity = targetRel.getTargetEntity();
prefetch.setEntityName(targetRel.getSourceEntity().getName());
String labelPrefix = dbPrefetch.getPath();
Set<String> seenNames = new HashSet<>();
for (ObjAttribute oa : targetEntity.getAttributes()) {
Iterator<CayenneMapEntry> dbPathIterator = oa.getDbPathIterator();
while (dbPathIterator.hasNext()) {
Object pathPart = dbPathIterator.next();
if (pathPart instanceof DbAttribute) {
DbAttribute attribute = (DbAttribute) pathPart;
if (seenNames.add(attribute.getName())) {
result.addDbField(labelPrefix + '.' + attribute.getName(), labelPrefix + '.' + attribute.getName());
}
}
}
}
// append remaining target attributes such as keys
DbEntity targetDbEntity = r.getTargetEntity();
for (DbAttribute attribute : targetDbEntity.getAttributes()) {
if (seenNames.add(attribute.getName())) {
result.addDbField(labelPrefix + '.' + attribute.getName(), labelPrefix + '.' + attribute.getName());
}
}
}
}
return result;
}
use of org.apache.cayenne.map.DbRelationship in project cayenne by apache.
the class SelectQueryMetadata method buildResultSetMappingForColumns.
/**
* Build DB result descriptor, that will be used to read and convert raw result of ColumnSelect
* @since 4.0
*/
private void buildResultSetMappingForColumns(SelectQuery<?> query, EntityResolver resolver) {
if (query.getColumns() == null || query.getColumns().isEmpty()) {
return;
}
SQLResult result = new SQLResult();
for (Property<?> column : query.getColumns()) {
Expression exp = column.getExpression();
String name = column.getName() == null ? exp.expName() : column.getName();
boolean fullObject = false;
if (exp.getType() == Expression.OBJ_PATH) {
// check if this is toOne relation
Expression dbPath = this.getObjEntity().translateToDbPath(exp);
DbRelationship rel = findRelationByPath(dbEntity, dbPath);
if (rel != null && !rel.isToMany()) {
// it this path is toOne relation, than select full object for it
fullObject = true;
}
} else if (exp.getType() == Expression.FULL_OBJECT) {
fullObject = true;
}
if (fullObject) {
// detected full object column
if (getPageSize() > 0) {
// for paginated queries keep only IDs
result.addEntityResult(buildEntityIdResultForColumn(column, resolver));
} else {
// will unwrap to full set of db-columns (with join prefetch optionally)
result.addEntityResult(buildEntityResultForColumn(query, column, resolver));
}
} else {
// scalar column
result.addColumnResult(name);
}
}
resultSetMapping = result.getResolvedComponents(resolver);
}
use of org.apache.cayenne.map.DbRelationship in project cayenne by apache.
the class ASTDbPath method toMap_AttchedObject_MultiStepPath.
private Map<?, ?> toMap_AttchedObject_MultiStepPath(ObjectContext context, Persistent persistent) {
Iterator<CayenneMapEntry> pathComponents = Cayenne.getObjEntity(persistent).getDbEntity().resolvePathComponents(this);
LinkedList<DbRelationship> reversedPathComponents = new LinkedList<>();
while (pathComponents.hasNext()) {
CayenneMapEntry component = pathComponents.next();
if (component instanceof DbRelationship) {
DbRelationship rel = (DbRelationship) component;
DbRelationship reverseRelationship = rel.getReverseRelationship();
if (reverseRelationship == null) {
reverseRelationship = rel.createReverseRelationship();
}
reversedPathComponents.addFirst(reverseRelationship);
} else {
// an attribute can only occur at the end of the path
break;
}
}
DbEntity finalEntity = reversedPathComponents.get(0).getSourceEntity();
StringBuilder reversedPathStr = new StringBuilder();
for (int i = 0; i < reversedPathComponents.size(); i++) {
reversedPathStr.append(reversedPathComponents.get(i).getName());
if (i < reversedPathComponents.size() - 1) {
reversedPathStr.append('.');
}
}
return ObjectSelect.dbQuery(finalEntity.getName()).where(ExpressionFactory.matchDbExp(reversedPathStr.toString(), persistent)).selectOne(context);
}
use of org.apache.cayenne.map.DbRelationship in project cayenne by apache.
the class DbRelationshipHandlerTest method testParsing.
@Test
public void testParsing() throws Exception {
final DataMap map = new DataMap();
DbEntity entity = new DbEntity("ARTIST");
map.addDbEntity(entity);
assertEquals(0, entity.getRelationships().size());
parse("db-relationship", new HandlerFactory() {
@Override
public NamespaceAwareNestedTagHandler createHandler(NamespaceAwareNestedTagHandler parent) {
return new DbRelationshipHandler(parent, map);
}
});
assertEquals(1, entity.getRelationships().size());
DbRelationship relationship = entity.getRelationship("artistPaintings");
assertNotNull(relationship);
assertEquals("PAINTING", relationship.getTargetEntityName());
assertTrue(relationship.isToDependentPK());
assertTrue(relationship.isToMany());
assertEquals("ID", relationship.getJoins().get(0).getSourceName());
assertEquals("ARTIST_ID", relationship.getJoins().get(0).getTargetName());
}
Aggregations