use of org.apache.cayenne.map.DbJoin in project cayenne by apache.
the class DbRelationshipValidator method getJoins.
private String getJoins(DbRelationship relationship) {
List<String> joins = new ArrayList<>();
for (DbJoin join : relationship.getJoins()) {
joins.add("[source=" + join.getSourceName() + ",target=" + join.getTargetName() + "]");
}
Collections.sort(joins);
return Util.join(joins, ",");
}
use of org.apache.cayenne.map.DbJoin in project cayenne by apache.
the class ObjRelationshipValidator method validate.
void validate(ObjRelationship relationship, ValidationResult validationResult) {
if (Util.isEmptyString(relationship.getName())) {
addFailure(validationResult, relationship, "Unnamed ObjRelationship");
} else if (relationship.getSourceEntity().getAttribute(relationship.getName()) != null) {
// check if there are attributes having the same name
addFailure(validationResult, relationship, "ObjRelationship '%s' has the same name as one of ObjAttributes", toString(relationship));
} else {
NameValidationHelper helper = NameValidationHelper.getInstance();
String invalidChars = helper.invalidCharsInObjPathComponent(relationship.getName());
if (invalidChars != null) {
addFailure(validationResult, relationship, "ObjRelationship name '%s' contains invalid characters: %s", toString(relationship), invalidChars);
} else if (helper.invalidDataObjectProperty(relationship.getName())) {
addFailure(validationResult, relationship, "ObjRelationship name '%s' is a reserved word", toString(relationship));
}
}
if (relationship.getTargetEntity() == null) {
addFailure(validationResult, relationship, "ObjRelationship '%s' has no target entity", toString(relationship));
} else {
// check for missing DbRelationship mappings
List<DbRelationship> dbRels = relationship.getDbRelationships();
if (dbRels.isEmpty()) {
addFailure(validationResult, relationship, "ObjRelationship '%s' has no DbRelationship mapping", toString(relationship));
} else {
DbEntity expectedSrc = relationship.getSourceEntity().getDbEntity();
DbEntity expectedTarget = relationship.getTargetEntity().getDbEntity();
if ((dbRels.get(0)).getSourceEntity() != expectedSrc || (dbRels.get(dbRels.size() - 1)).getTargetEntity() != expectedTarget) {
addFailure(validationResult, relationship, "ObjRelationship '%s' has incomplete DbRelationship mapping", toString(relationship));
}
}
}
// foreign key attributes are mandatory.
if (relationship.isToMany() && !relationship.isFlattened() && (relationship.getDeleteRule() == DeleteRule.NULLIFY)) {
ObjRelationship inverse = relationship.getReverseRelationship();
if (inverse != null) {
DbRelationship firstRel = inverse.getDbRelationships().get(0);
Iterator<DbJoin> attributePairIterator = firstRel.getJoins().iterator();
// by default, the relation will be check for mandatory.
boolean check = true;
while (attributePairIterator.hasNext()) {
DbJoin pair = attributePairIterator.next();
if (!pair.getSource().isMandatory()) {
// a field of the fk can be nullable, cancel the check.
check = false;
break;
}
}
if (check) {
addFailure(validationResult, relationship, "ObjRelationship '%s' has a Nullify delete rule and a mandatory reverse relationship", toString(relationship));
}
}
}
// check for relationships with same source and target entities
ObjEntity entity = relationship.getSourceEntity();
for (ObjRelationship rel : entity.getRelationships()) {
if (relationship.getDbRelationshipPath() != null && relationship.getDbRelationshipPath().equals(rel.getDbRelationshipPath())) {
if (relationship != rel && relationship.getTargetEntity() == rel.getTargetEntity() && relationship.getSourceEntity() == rel.getSourceEntity()) {
addFailure(validationResult, relationship, "ObjectRelationship '%s' duplicates relationship '%s'", toString(relationship), toString(rel));
}
}
}
// check for invalid relationships in inherited entities
if (relationship.getReverseRelationship() != null) {
ObjRelationship revRel = relationship.getReverseRelationship();
if (relationship.getSourceEntity() != revRel.getTargetEntity() || relationship.getTargetEntity() != revRel.getSourceEntity()) {
addFailure(validationResult, revRel, "Usage of super entity's relationships '%s' as reversed relationships for sub entity is discouraged", toString(revRel));
}
}
checkForDuplicates(relationship, validationResult);
}
use of org.apache.cayenne.map.DbJoin in project cayenne by apache.
the class AshwoodEntitySorter method doIndexSorter.
/**
* Reindexes internal sorter without synchronization.
*/
protected void doIndexSorter() {
Map<DbEntity, List<DbRelationship>> reflexiveDbEntities = new HashMap<>();
Digraph<DbEntity, List<DbAttribute>> referentialDigraph = new MapDigraph<>();
if (entityResolver != null) {
for (DbEntity entity : entityResolver.getDbEntities()) {
referentialDigraph.addVertex(entity);
}
}
for (DbEntity destination : entityResolver.getDbEntities()) {
for (DbRelationship candidate : destination.getRelationships()) {
if ((!candidate.isToMany() && !candidate.isToDependentPK()) || candidate.isToMasterPK()) {
DbEntity origin = candidate.getTargetEntity();
boolean newReflexive = destination.equals(origin);
for (DbJoin join : candidate.getJoins()) {
DbAttribute targetAttribute = join.getTarget();
if (targetAttribute.isPrimaryKey()) {
if (newReflexive) {
List<DbRelationship> reflexiveRels = reflexiveDbEntities.get(destination);
if (reflexiveRels == null) {
reflexiveRels = new ArrayList<>(1);
reflexiveDbEntities.put(destination, reflexiveRels);
}
reflexiveRels.add(candidate);
newReflexive = false;
}
List<DbAttribute> fks = referentialDigraph.getArc(origin, destination);
if (fks == null) {
fks = new ArrayList<>();
referentialDigraph.putArc(origin, destination, fks);
}
fks.add(targetAttribute);
}
}
}
}
}
StrongConnection<DbEntity, List<DbAttribute>> contractor = new StrongConnection<>(referentialDigraph);
Digraph<Collection<DbEntity>, Collection<List<DbAttribute>>> contractedReferentialDigraph = new MapDigraph<>();
contractor.contract(contractedReferentialDigraph);
IndegreeTopologicalSort<Collection<DbEntity>> sorter = new IndegreeTopologicalSort<>(contractedReferentialDigraph);
Map<DbEntity, ComponentRecord> components = new HashMap<>(contractedReferentialDigraph.order());
int componentIndex = 0;
while (sorter.hasNext()) {
Collection<DbEntity> component = sorter.next();
ComponentRecord rec = new ComponentRecord(componentIndex++, component);
for (DbEntity table : component) {
components.put(table, rec);
}
}
this.reflexiveDbEntities = reflexiveDbEntities;
this.components = components;
}
use of org.apache.cayenne.map.DbJoin in project cayenne by apache.
the class DbRelationshipHandler method createDbAttributePair.
private void createDbAttributePair(Attributes attributes) {
DbJoin join = new DbJoin(dbRelationship);
join.setSourceName(attributes.getValue("source"));
join.setTargetName(attributes.getValue("target"));
dbRelationship.addJoin(join);
}
use of org.apache.cayenne.map.DbJoin in project cayenne by apache.
the class JdbcAdapter method createFkConstraint.
/**
* Returns a SQL string that can be used to create a foreign key constraint
* for the relationship.
*/
@Override
public String createFkConstraint(DbRelationship rel) {
DbEntity source = rel.getSourceEntity();
StringBuilder buf = new StringBuilder();
StringBuilder refBuf = new StringBuilder();
buf.append("ALTER TABLE ");
buf.append(quotingStrategy.quotedFullyQualifiedName(source));
buf.append(" ADD FOREIGN KEY (");
boolean first = true;
for (DbJoin join : rel.getJoins()) {
if (first) {
first = false;
} else {
buf.append(", ");
refBuf.append(", ");
}
buf.append(quotingStrategy.quotedSourceName(join));
refBuf.append(quotingStrategy.quotedTargetName(join));
}
buf.append(") REFERENCES ");
buf.append(quotingStrategy.quotedFullyQualifiedName(rel.getTargetEntity()));
buf.append(" (").append(refBuf.toString()).append(')');
return buf.toString();
}
Aggregations