Search in sources :

Example 56 with DbRelationship

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;
}
Also used : ObjRelationship(org.apache.cayenne.map.ObjRelationship) ClassDescriptor(org.apache.cayenne.reflect.ClassDescriptor) ObjAttribute(org.apache.cayenne.map.ObjAttribute) CayenneRuntimeException(org.apache.cayenne.CayenneRuntimeException) Fault(org.apache.cayenne.Fault) Persistent(org.apache.cayenne.Persistent) AttributeProperty(org.apache.cayenne.reflect.AttributeProperty) DataRow(org.apache.cayenne.DataRow) ToOneProperty(org.apache.cayenne.reflect.ToOneProperty) ObjEntity(org.apache.cayenne.map.ObjEntity) ToManyProperty(org.apache.cayenne.reflect.ToManyProperty) DbRelationship(org.apache.cayenne.map.DbRelationship) DbJoin(org.apache.cayenne.map.DbJoin) DataObject(org.apache.cayenne.DataObject) Map(java.util.Map) PropertyVisitor(org.apache.cayenne.reflect.PropertyVisitor)

Example 57 with DbRelationship

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;
        }
    });
}
Also used : ObjRelationship(org.apache.cayenne.map.ObjRelationship) ToManyProperty(org.apache.cayenne.reflect.ToManyProperty) ObjectId(org.apache.cayenne.ObjectId) DbRelationship(org.apache.cayenne.map.DbRelationship) AttributeProperty(org.apache.cayenne.reflect.AttributeProperty) PropertyVisitor(org.apache.cayenne.reflect.PropertyVisitor) ToOneProperty(org.apache.cayenne.reflect.ToOneProperty)

Example 58 with DbRelationship

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;
}
Also used : DbRelationship(org.apache.cayenne.map.DbRelationship) ArrayList(java.util.ArrayList) DataMap(org.apache.cayenne.map.DataMap)

Example 59 with DbRelationship

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;
}
Also used : EntitySorter(org.apache.cayenne.map.EntitySorter) AshwoodEntitySorter(org.apache.cayenne.ashwood.AshwoodEntitySorter) DbEntity(org.apache.cayenne.map.DbEntity) AshwoodEntitySorter(org.apache.cayenne.ashwood.AshwoodEntitySorter) DbRelationship(org.apache.cayenne.map.DbRelationship) ArrayList(java.util.ArrayList) DbAttribute(org.apache.cayenne.map.DbAttribute) DbJoin(org.apache.cayenne.map.DbJoin) EntityResolver(org.apache.cayenne.map.EntityResolver)

Example 60 with DbRelationship

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;
}
Also used : HashMap(java.util.HashMap) DbRelationship(org.apache.cayenne.map.DbRelationship) CayenneRuntimeException(org.apache.cayenne.CayenneRuntimeException) DbJoin(org.apache.cayenne.map.DbJoin)

Aggregations

DbRelationship (org.apache.cayenne.map.DbRelationship)106 DbEntity (org.apache.cayenne.map.DbEntity)59 DbAttribute (org.apache.cayenne.map.DbAttribute)35 DbJoin (org.apache.cayenne.map.DbJoin)35 ObjEntity (org.apache.cayenne.map.ObjEntity)30 ObjRelationship (org.apache.cayenne.map.ObjRelationship)28 ObjAttribute (org.apache.cayenne.map.ObjAttribute)20 Test (org.junit.Test)15 ClassDescriptor (org.apache.cayenne.reflect.ClassDescriptor)13 ArrayList (java.util.ArrayList)11 CayenneRuntimeException (org.apache.cayenne.CayenneRuntimeException)10 EJBQLException (org.apache.cayenne.ejbql.EJBQLException)9 DataMap (org.apache.cayenne.map.DataMap)9 Entity (org.apache.cayenne.map.Entity)8 AttributeProperty (org.apache.cayenne.reflect.AttributeProperty)8 PropertyVisitor (org.apache.cayenne.reflect.PropertyVisitor)8 ToManyProperty (org.apache.cayenne.reflect.ToManyProperty)8 ToOneProperty (org.apache.cayenne.reflect.ToOneProperty)8 HashMap (java.util.HashMap)6 ObjectId (org.apache.cayenne.ObjectId)6