use of org.apache.cayenne.map.DbRelationship 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.DbRelationship in project cayenne by apache.
the class DataRowUtils method forceMergeWithSnapshot.
static void forceMergeWithSnapshot(final DataContext context, ClassDescriptor descriptor, final Persistent object, final DataRow snapshot) {
final ObjectDiff diff = context.getObjectStore().getChangesByObjectId().get(object.getObjectId());
descriptor.visitProperties(new PropertyVisitor() {
public boolean visitAttribute(AttributeProperty property) {
String dbAttrPath = property.getAttribute().getDbAttributePath();
// supports merging of partial snapshots...
// check for null is cheaper than double lookup
// for a key... so check for partial snapshot
// only if the value is null
Object newValue = snapshot.get(dbAttrPath);
if (newValue != null || snapshot.containsKey(dbAttrPath)) {
Object curValue = property.readPropertyDirectly(object);
Object oldValue = diff != null ? diff.getSnapshotValue(property.getName()) : null;
// otherwise leave it alone
if (Util.nullSafeEquals(curValue, oldValue) && !Util.nullSafeEquals(newValue, curValue)) {
property.writePropertyDirectly(object, oldValue, newValue);
}
}
return true;
}
public boolean visitToMany(ToManyProperty property) {
// noop - nothing to merge
return true;
}
public boolean visitToOne(ToOneProperty property) {
ObjRelationship relationship = property.getRelationship();
if (relationship.isToPK()) {
// otherwise leave it alone
if (!isToOneTargetModified(property, object, diff)) {
DbRelationship dbRelationship = relationship.getDbRelationships().get(0);
// snapshots
if (hasFK(dbRelationship, snapshot)) {
ObjectId id = snapshot.createTargetObjectId(relationship.getTargetEntityName(), dbRelationship);
if (diff == null || !diff.containsArcSnapshot(relationship.getName()) || !Util.nullSafeEquals(id, diff.getArcSnapshotValue(relationship.getName()))) {
if (id == null) {
property.writeProperty(object, null, null);
} else {
// .. must turn to fault instead
if (!relationship.isSourceDefiningTargetPrecenseAndType(context.getEntityResolver())) {
property.invalidate(object);
} else {
property.writeProperty(object, null, context.findOrCreateObject(id));
}
}
}
}
}
}
return true;
}
});
}
use of org.apache.cayenne.map.DbRelationship in project cayenne by apache.
the class DbGenerator method createConstraintsQueries.
/**
* Creates FK and UNIQUE constraint statements for a given table.
*
* @since 3.0
*/
public List<String> createConstraintsQueries(DbEntity table) {
List<String> list = new ArrayList<>();
for (final DbRelationship rel : table.getRelationships()) {
if (rel.isToMany()) {
continue;
}
// skip FK to a different DB
if (domain != null) {
DataMap srcMap = rel.getSourceEntity().getDataMap();
DataMap targetMap = rel.getTargetEntity().getDataMap();
if (srcMap != null && targetMap != null && srcMap != targetMap) {
if (domain.lookupDataNode(srcMap) != domain.lookupDataNode(targetMap)) {
continue;
}
}
}
if (rel.isToPK() && !rel.isToDependentPK()) {
if (getAdapter().supportsUniqueConstraints()) {
DbRelationship reverse = rel.getReverseRelationship();
if (reverse != null && !reverse.isToMany() && !reverse.isToPK()) {
String unique = getAdapter().createUniqueConstraint((DbEntity) rel.getSourceEntity(), rel.getSourceAttributes());
if (unique != null) {
list.add(unique);
}
}
}
String fk = getAdapter().createFkConstraint(rel);
if (fk != null) {
list.add(fk);
}
}
}
return list;
}
use of org.apache.cayenne.map.DbRelationship 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.DbRelationship 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;
}
Aggregations