use of org.apache.cayenne.map.DbJoin in project cayenne by apache.
the class DataContext method currentSnapshot.
/**
* Returns a DataRow reflecting current, possibly uncommitted, object state.
* <p>
* <strong>Warning:</strong> This method will return a partial snapshot if
* an object or one of its related objects that propagate their keys to this
* object have temporary ids. DO NOT USE this method if you expect a DataRow
* to represent a complete object state.
* </p>
*
* @since 1.1
*/
public DataRow currentSnapshot(final Persistent object) {
// for a HOLLOW object return snapshot from cache
if (object.getPersistenceState() == PersistenceState.HOLLOW && object.getObjectContext() != null) {
return getObjectStore().getSnapshot(object.getObjectId());
}
ObjEntity entity = getEntityResolver().getObjEntity(object);
final ClassDescriptor descriptor = getEntityResolver().getClassDescriptor(entity.getName());
final DataRow snapshot = new DataRow(10);
snapshot.setEntityName(entity.getName());
descriptor.visitProperties(new PropertyVisitor() {
public boolean visitAttribute(AttributeProperty property) {
ObjAttribute objAttr = property.getAttribute();
// processing compound attributes correctly
snapshot.put(objAttr.getDbAttributePath(), property.readPropertyDirectly(object));
return true;
}
public boolean visitToMany(ToManyProperty property) {
// do nothing
return true;
}
public boolean visitToOne(ToOneProperty property) {
ObjRelationship rel = property.getRelationship();
// if target doesn't propagates its key value, skip it
if (rel.isSourceIndependentFromTargetChange()) {
return true;
}
Object targetObject = property.readPropertyDirectly(object);
if (targetObject == null) {
return true;
}
// to avoid unneeded fault triggering
if (targetObject instanceof Fault) {
DataRow storedSnapshot = getObjectStore().getSnapshot(object.getObjectId());
if (storedSnapshot == null) {
throw new CayenneRuntimeException("No matching objects found for ObjectId %s" + ". Object may have been deleted externally.", object.getObjectId());
}
DbRelationship dbRel = rel.getDbRelationships().get(0);
for (DbJoin join : dbRel.getJoins()) {
String key = join.getSourceName();
snapshot.put(key, storedSnapshot.get(key));
}
return true;
}
// target is resolved and we have an FK->PK to it,
// so extract it from target...
Persistent target = (Persistent) targetObject;
Map<String, Object> idParts = target.getObjectId().getIdSnapshot();
// this method.
if (idParts.isEmpty()) {
return true;
}
DbRelationship dbRel = rel.getDbRelationships().get(0);
Map<String, Object> fk = dbRel.srcFkSnapshotWithTargetSnapshot(idParts);
snapshot.putAll(fk);
return true;
}
});
// process object id map
// we should ignore any object id values if a corresponding attribute
// is a part of relationship "toMasterPK", since those values have been
// set above when db relationships where processed.
Map<String, Object> thisIdParts = object.getObjectId().getIdSnapshot();
if (thisIdParts != null) {
// put only those that do not exist in the map
for (Map.Entry<String, Object> entry : thisIdParts.entrySet()) {
String nextKey = entry.getKey();
if (!snapshot.containsKey(nextKey)) {
snapshot.put(nextKey, entry.getValue());
}
}
}
return snapshot;
}
use of org.apache.cayenne.map.DbJoin in project cayenne by apache.
the class DbGenerator method prepareDbEntities.
/**
* Helper method that orders DbEntities to satisfy referential constraints
* and returns an ordered list. It also filters out DerivedDbEntities.
*/
private void prepareDbEntities(Collection<DbEntity> excludedEntities) {
if (excludedEntities == null) {
excludedEntities = Collections.emptyList();
}
List<DbEntity> tables = new ArrayList<>();
List<DbEntity> tablesWithAutoPk = new ArrayList<>();
for (DbEntity nextEntity : map.getDbEntities()) {
// tables with no columns are not included
if (nextEntity.getAttributes().size() == 0) {
logObj.info("Skipping entity with no attributes: " + nextEntity.getName());
continue;
}
// check if this entity is explicitly excluded
if (excludedEntities.contains(nextEntity)) {
continue;
}
// tables with invalid DbAttributes are not included
boolean invalidAttributes = false;
for (final DbAttribute attr : nextEntity.getAttributes()) {
if (attr.getType() == TypesMapping.NOT_DEFINED) {
logObj.info("Skipping entity, attribute type is undefined: " + nextEntity.getName() + "." + attr.getName());
invalidAttributes = true;
break;
}
}
if (invalidAttributes) {
continue;
}
tables.add(nextEntity);
// check if an automatic PK generation can be potentially supported
// in this entity. For now simply check that the key is not
// propagated
Iterator<DbRelationship> relationships = nextEntity.getRelationships().iterator();
// create a copy of the original PK list,
// since the list will be modified locally
List<DbAttribute> pkAttributes = new ArrayList<>(nextEntity.getPrimaryKeys());
while (pkAttributes.size() > 0 && relationships.hasNext()) {
DbRelationship nextRelationship = relationships.next();
if (!nextRelationship.isToMasterPK()) {
continue;
}
// so
for (DbJoin join : nextRelationship.getJoins()) {
pkAttributes.remove(join.getSource());
}
}
// is not propagated via relationship
if (pkAttributes.size() > 0) {
tablesWithAutoPk.add(nextEntity);
}
}
// sort table list
if (tables.size() > 1) {
EntitySorter sorter = new AshwoodEntitySorter();
sorter.setEntityResolver(new EntityResolver(Collections.singleton(map)));
sorter.sortDbEntities(tables, false);
}
this.dbEntitiesInInsertOrder = tables;
this.dbEntitiesRequiringAutoPK = tablesWithAutoPk;
}
use of org.apache.cayenne.map.DbJoin in project cayenne by apache.
the class FlattenedArcKey method eagerJoinSnapshot.
private Map<String, Object> eagerJoinSnapshot() {
List<DbRelationship> relList = relationship.getDbRelationships();
if (relList.size() != 2) {
throw new CayenneRuntimeException("Only single-step flattened relationships are supported in this operation: %s", relationship);
}
DbRelationship firstDbRel = relList.get(0);
DbRelationship secondDbRel = relList.get(1);
// here ordering of ids is determined by 'relationship', so use id1, id2
// instead of orderedIds
Map<String, ?> sourceId = id1.getSourceId().getIdSnapshot();
Map<String, ?> destinationId = id2.getSourceId().getIdSnapshot();
Map<String, Object> snapshot = new HashMap<>(sourceId.size() + destinationId.size(), 1);
for (DbJoin join : firstDbRel.getJoins()) {
snapshot.put(join.getTargetName(), sourceId.get(join.getSourceName()));
}
for (DbJoin join : secondDbRel.getJoins()) {
snapshot.put(join.getSourceName(), destinationId.get(join.getTargetName()));
}
return snapshot;
}
use of org.apache.cayenne.map.DbJoin in project cayenne by apache.
the class DropRelationshipToModelIT method testForeignKey.
@Test
public void testForeignKey() 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);
// create db relationships
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());
assertTokensAndExecute(3, 0);
assertTokensAndExecute(0, 0);
// 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());
// remove relationship and fk from model, merge to db and read to model
dbEntity2.removeRelationship(rel2To1.getName());
dbEntity1.removeRelationship(rel1To2.getName());
dbEntity2.removeAttribute(e2col2.getName());
List<MergerToken> tokens = createMergeTokens();
/**
* Drop Relationship NEW_TABLE2->NEW_TABLE To DB
* Drop Column NEW_TABLE2.FK To DB
*/
assertTokens(tokens, 2, 0);
for (MergerToken token : tokens) {
if (token.getDirection().isToDb()) {
execute(token);
}
}
assertTokensAndExecute(0, 0);
dbEntity2.addRelationship(rel2To1);
dbEntity1.addRelationship(rel1To2);
dbEntity2.addAttribute(e2col2);
// try do use the merger to remove the relationship in the model
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();
}
execute(token0);
execute(token1);
// 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);
}
use of org.apache.cayenne.map.DbJoin in project cayenne by apache.
the class DefaultObjectNameGeneratorTest method makeRelationship.
private DbRelationship makeRelationship(String srcEntity, String srcKey, String targetEntity, String targetKey, boolean toMany) {
DbRelationship relationship = new DbRelationship();
relationship.addJoin(new DbJoin(relationship, srcKey, targetKey));
relationship.setToMany(toMany);
relationship.setSourceEntity(new DbEntity(srcEntity));
relationship.setTargetEntityName(targetEntity);
return relationship;
}
Aggregations