use of org.apache.cayenne.map.ObjRelationship in project cayenne by apache.
the class BaseDataObject method validateForSave.
/**
* Performs property validation of the object, appending any validation
* failures to the provided validationResult object. This method is invoked
* from "validateFor.." before committing a NEW or MODIFIED object to the
* database. Validation includes checking for null values and value sizes.
* CayenneDataObject subclasses may override this method, calling super.
*
* @since 1.1
*/
protected void validateForSave(ValidationResult validationResult) {
ObjEntity objEntity = getObjectContext().getEntityResolver().getObjEntity(this);
if (objEntity == null) {
throw new CayenneRuntimeException("No ObjEntity mapping found for DataObject %s", getClass().getName());
}
// validate mandatory attributes
Map<String, ValidationFailure> failedDbAttributes = null;
for (ObjAttribute next : objEntity.getAttributes()) {
// TODO: andrus, 2/20/2007 - handle embedded attribute
if (next instanceof EmbeddedAttribute) {
continue;
}
DbAttribute dbAttribute = next.getDbAttribute();
if (dbAttribute == null) {
throw new CayenneRuntimeException("ObjAttribute '%s" + "' does not have a corresponding DbAttribute", next.getName());
}
// pk may still be generated
if (dbAttribute.isPrimaryKey()) {
continue;
}
Object value = this.readPropertyDirectly(next.getName());
if (dbAttribute.isMandatory()) {
ValidationFailure failure = BeanValidationFailure.validateNotNull(this, next.getName(), value);
if (failure != null) {
if (failedDbAttributes == null) {
failedDbAttributes = new HashMap<>();
}
failedDbAttributes.put(dbAttribute.getName(), failure);
continue;
}
}
// validate length
if (value != null && dbAttribute.getMaxLength() > 0) {
if (value.getClass().isArray()) {
int len = Array.getLength(value);
if (len > dbAttribute.getMaxLength()) {
String message = "\"" + next.getName() + "\" exceeds maximum allowed length (" + dbAttribute.getMaxLength() + " bytes): " + len;
validationResult.addFailure(new BeanValidationFailure(this, next.getName(), message));
}
} else if (value instanceof CharSequence) {
int len = ((CharSequence) value).length();
if (len > dbAttribute.getMaxLength()) {
String message = "\"" + next.getName() + "\" exceeds maximum allowed length (" + dbAttribute.getMaxLength() + " chars): " + len;
validationResult.addFailure(new BeanValidationFailure(this, next.getName(), message));
}
}
}
}
// validate mandatory relationships
for (final ObjRelationship relationship : objEntity.getRelationships()) {
List<DbRelationship> dbRels = relationship.getDbRelationships();
if (dbRels.isEmpty()) {
continue;
}
// see ObjRelationship.recalculateReadOnlyValue() for more info
if (relationship.isSourceIndependentFromTargetChange()) {
continue;
}
// if db relationship is not based on a PK and is based on mandatory
// attributes, see if we have a target object set
// relationship will be validated only if all db path has mandatory
// db relationships
boolean validate = true;
for (DbRelationship dbRelationship : dbRels) {
for (DbJoin join : dbRelationship.getJoins()) {
DbAttribute source = join.getSource();
if (source.isMandatory()) {
// clear attribute failures...
if (failedDbAttributes != null && !failedDbAttributes.isEmpty()) {
failedDbAttributes.remove(source.getName());
}
} else {
// do not validate if the relation is based on
// multiple keys with some that can be nullable.
validate = false;
}
}
}
if (validate) {
Object value = this.readPropertyDirectly(relationship.getName());
ValidationFailure failure = BeanValidationFailure.validateNotNull(this, relationship.getName(), value);
if (failure != null) {
validationResult.addFailure(failure);
}
}
}
// deal with previously found attribute failures...
if (failedDbAttributes != null && !failedDbAttributes.isEmpty()) {
for (ValidationFailure failure : failedDbAttributes.values()) {
validationResult.addFailure(failure);
}
}
}
use of org.apache.cayenne.map.ObjRelationship in project cayenne by apache.
the class BaseDataObject method unsetReverseRelationship.
/**
* Removes current object from reverse relationship of object
* <code>val</code> to this object.
*/
protected void unsetReverseRelationship(String relName, DataObject val) {
EntityResolver resolver = objectContext.getEntityResolver();
ObjEntity entity = resolver.getObjEntity(objectId.getEntityName());
if (entity == null) {
throw new IllegalStateException("DataObject's entity is unmapped, objectId: " + objectId);
}
ObjRelationship rel = entity.getRelationship(relName);
ObjRelationship revRel = rel.getReverseRelationship();
if (revRel != null) {
if (revRel.isToMany()) {
val.removeToManyTarget(revRel.getName(), this, false);
} else {
val.setToOneTarget(revRel.getName(), null, false);
}
}
}
use of org.apache.cayenne.map.ObjRelationship in project cayenne by apache.
the class DataDomainIndirectDiffBuilder method arcCreated.
@Override
public void arcCreated(Object nodeId, Object targetNodeId, Object arcId) {
ObjEntity entity = resolver.getObjEntity(((ObjectId) nodeId).getEntityName());
ObjRelationship relationship = entity.getRelationship(arcId.toString());
if (relationship.isSourceIndependentFromTargetChange()) {
ObjectId nodeObjectId = (ObjectId) nodeId;
if (!nodeObjectId.isTemporary()) {
indirectModifications.add(nodeObjectId);
}
if (relationship.isFlattened()) {
if (relationship.isReadOnly()) {
throw new CayenneRuntimeException("Cannot set the read-only flattened relationship '%s' in ObjEntity '%s'.", relationship.getName(), relationship.getSourceEntity().getName());
}
// Register this combination (so we can remove it later if an insert occurs before commit)
FlattenedArcKey key = new FlattenedArcKey((ObjectId) nodeId, (ObjectId) targetNodeId, relationship);
// If this combination has already been deleted, simply undelete it.
if (!flattenedDeletes.remove(key)) {
flattenedInserts.add(key);
}
}
}
}
use of org.apache.cayenne.map.ObjRelationship in project cayenne by apache.
the class DataDomainQueryAction method interceptRelationshipQuery.
private boolean interceptRelationshipQuery() {
if (query instanceof RelationshipQuery) {
RelationshipQuery relationshipQuery = (RelationshipQuery) query;
if (relationshipQuery.isRefreshing()) {
return !DONE;
}
ObjRelationship relationship = relationshipQuery.getRelationship(domain.getEntityResolver());
// check if we can derive target PK from FK...
if (relationship.isSourceIndependentFromTargetChange()) {
return !DONE;
}
// we can assume that there is one and only one DbRelationship as
// we previously checked that "!isSourceIndependentFromTargetChange"
DbRelationship dbRelationship = relationship.getDbRelationships().get(0);
// FK pointing to a unique field that is a 'fake' PK (CAY-1755)...
// It is not sufficient to generate target ObjectId.
DbEntity targetEntity = dbRelationship.getTargetEntity();
if (dbRelationship.getJoins().size() < targetEntity.getPrimaryKeys().size()) {
return !DONE;
}
if (cache == null) {
return !DONE;
}
DataRow sourceRow = cache.getCachedSnapshot(relationshipQuery.getObjectId());
if (sourceRow == null) {
return !DONE;
}
ObjectId targetId = sourceRow.createTargetObjectId(relationship.getTargetEntityName(), dbRelationship);
// null id means that FK is null...
if (targetId == null) {
this.response = new GenericResponse(Collections.EMPTY_LIST);
return DONE;
}
// target id resolution (unlike source) should be polymorphic
DataRow targetRow = polymorphicRowFromCache(targetId);
if (targetRow != null) {
this.response = new GenericResponse(Collections.singletonList(targetRow));
return DONE;
}
// create a fault
if (context != null && relationship.isSourceDefiningTargetPrecenseAndType(domain.getEntityResolver())) {
// prevent passing partial snapshots to ObjectResolver per
// CAY-724.
// Create a hollow object right here and skip object conversion
// downstream
this.noObjectConversion = true;
Object object = context.findOrCreateObject(targetId);
this.response = new GenericResponse(Collections.singletonList(object));
return DONE;
}
}
return !DONE;
}
use of org.apache.cayenne.map.ObjRelationship in project cayenne by apache.
the class DataNodeSyncQualifierDescriptor method reset.
void reset(DbEntityClassDescriptor descriptor) {
attributes = new ArrayList<>(3);
valueTransformers = new ArrayList<>(3);
usingOptimisticLocking = descriptor.getEntity().getLockType() == ObjEntity.LOCK_TYPE_OPTIMISTIC;
// master PK columns
if (descriptor.isMaster()) {
for (final DbAttribute attribute : descriptor.getDbEntity().getPrimaryKeys()) {
attributes.add(attribute);
valueTransformers.add(input -> {
ObjectId id = (ObjectId) input.getNodeId();
return id.getIdSnapshot().get(attribute.getName());
});
}
} else {
// TODO: andrus 12/23/2007 - only one step relationship is supported...
if (descriptor.getPathFromMaster().size() != 1) {
throw new CayenneRuntimeException("Only single step dependent relationships are currently supported. Actual path length: %d", descriptor.getPathFromMaster().size());
}
DbRelationship masterDependentDbRel = descriptor.getPathFromMaster().get(0);
if (masterDependentDbRel != null) {
for (final DbJoin dbAttrPair : masterDependentDbRel.getJoins()) {
DbAttribute dbAttribute = dbAttrPair.getTarget();
if (!attributes.contains(dbAttribute)) {
attributes.add(dbAttribute);
valueTransformers.add(input -> {
ObjectId id = (ObjectId) input.getNodeId();
return id.getIdSnapshot().get(dbAttrPair.getSourceName());
});
}
}
}
}
if (usingOptimisticLocking) {
for (final ObjAttribute attribute : descriptor.getEntity().getAttributes()) {
if (attribute.isUsedForLocking()) {
// only care about first step in a flattened attribute
DbAttribute dbAttribute = (DbAttribute) attribute.getDbPathIterator().next();
// only use qualifier if dbEntities match
if (dbAttribute.getEntity().equals(descriptor.getDbEntity()) && !attributes.contains(dbAttribute)) {
attributes.add(dbAttribute);
valueTransformers.add(input -> input.getSnapshotValue(attribute.getName()));
}
}
}
for (final ObjRelationship relationship : descriptor.getEntity().getRelationships()) {
if (relationship.isUsedForLocking()) {
// only care about the first DbRelationship
DbRelationship dbRelationship = relationship.getDbRelationships().get(0);
for (final DbJoin dbAttrPair : dbRelationship.getJoins()) {
DbAttribute dbAttribute = dbAttrPair.getSource();
// relationship transformers override attribute transformers for meaningful FK's...
// why meaningful FKs can go out of sync is another story (CAY-595)
int index = attributes.indexOf(dbAttribute);
if (index >= 0 && !dbAttribute.isForeignKey()) {
continue;
}
Function<ObjectDiff, Object> transformer = input -> {
ObjectId targetId = input.getArcSnapshotValue(relationship.getName());
return targetId != null ? targetId.getIdSnapshot().get(dbAttrPair.getTargetName()) : null;
};
if (index < 0) {
attributes.add(dbAttribute);
valueTransformers.add(transformer);
} else {
valueTransformers.set(index, transformer);
}
}
}
}
}
}
Aggregations