use of io.micronaut.data.model.PersistentAssociationPath in project micronaut-data by micronaut-projects.
the class AbstractCascadeOperations method afterCascadedOne.
/**
* Process after a child element has been cascaded.
*
* @param entity The parent entity.
* @param associations The association leading to the child
* @param prevChild The previous child value
* @param newChild The new child value
* @param <T> The entity type
* @return The entity instance
*/
protected <T> T afterCascadedOne(T entity, List<Association> associations, Object prevChild, Object newChild) {
RuntimeAssociation<Object> association = (RuntimeAssociation<Object>) associations.iterator().next();
if (associations.size() == 1) {
if (association.isForeignKey()) {
PersistentAssociationPath inverse = association.getInversePathSide().orElse(null);
if (inverse != null) {
// don't cast to BeanProperty<T..> here because its the inverse, so we want to set the entity onto the newChild
newChild = inverse.setPropertyValue(newChild, entity);
}
}
if (prevChild != newChild) {
entity = setProperty((BeanProperty<T, Object>) association.getProperty(), entity, newChild);
}
return entity;
} else {
BeanProperty<T, Object> property = (BeanProperty<T, Object>) association.getProperty();
Object innerEntity = property.get(entity);
Object newInnerEntity = afterCascadedOne(innerEntity, associations.subList(1, associations.size()), prevChild, newChild);
if (newInnerEntity != innerEntity) {
innerEntity = convertAndSetWithValue(property, entity, newInnerEntity);
}
return (T) innerEntity;
}
}
use of io.micronaut.data.model.PersistentAssociationPath in project micronaut-data by micronaut-projects.
the class SqlResultEntityTypeMapper method setChildrenAndTriggerPostLoad.
private Object setChildrenAndTriggerPostLoad(Object instance, MappingContext<?> ctx, Object parent) {
if (ctx.manyAssociations != null) {
List<Object> values = new ArrayList<>(ctx.manyAssociations.size());
for (MappingContext associationCtx : ctx.manyAssociations.values()) {
values.add(setChildrenAndTriggerPostLoad(associationCtx.entity, associationCtx, parent));
}
return values;
} else if (ctx.associations != null) {
for (Map.Entry<Association, MappingContext> e : ctx.associations.entrySet()) {
MappingContext associationCtx = e.getValue();
RuntimeAssociation runtimeAssociation = (RuntimeAssociation) e.getKey();
BeanProperty beanProperty = runtimeAssociation.getProperty();
if (runtimeAssociation.getKind().isSingleEnded() && (associationCtx.manyAssociations == null || associationCtx.manyAssociations.isEmpty())) {
Object value = beanProperty.get(instance);
Object newValue = setChildrenAndTriggerPostLoad(value, associationCtx, instance);
if (newValue != value) {
instance = setProperty(beanProperty, instance, newValue);
}
} else {
Object newValue = setChildrenAndTriggerPostLoad(null, associationCtx, instance);
newValue = resultReader.convertRequired(newValue == null ? new ArrayList<>() : newValue, beanProperty.getType());
instance = setProperty(beanProperty, instance, newValue);
}
}
}
if (instance != null && (ctx.association == null || ctx.jp != null)) {
if (parent != null && ctx.association != null && ctx.association.isBidirectional()) {
PersistentAssociationPath inverse = ctx.association.getInversePathSide().orElseThrow(IllegalStateException::new);
Association association = inverse.getAssociation();
if (association.getKind().isSingleEnded()) {
Object inverseInstance = inverse.getPropertyValue(instance);
if (inverseInstance != parent) {
instance = inverse.setPropertyValue(instance, parent);
}
}
}
triggerPostLoad(ctx.persistentEntity, instance);
}
return instance;
}
use of io.micronaut.data.model.PersistentAssociationPath in project micronaut-data by micronaut-projects.
the class AbstractCascadeOperations method afterCascadedMany.
/**
* Process after a children element has been cascaded.
*
* @param entity The parent entity.
* @param associations The association leading to the child
* @param prevChildren The previous children value
* @param newChildren The new children value
* @param <T> The entity type
* @return The entity instance
*/
protected <T> T afterCascadedMany(T entity, List<Association> associations, Iterable<Object> prevChildren, List<Object> newChildren) {
RuntimeAssociation<Object> association = (RuntimeAssociation<Object>) associations.iterator().next();
if (associations.size() == 1) {
for (ListIterator<Object> iterator = newChildren.listIterator(); iterator.hasNext(); ) {
Object c = iterator.next();
if (association.isForeignKey()) {
PersistentAssociationPath inverse = association.getInversePathSide().orElse(null);
if (inverse != null) {
Object newc = inverse.setPropertyValue(c, entity);
if (c != newc) {
iterator.set(newc);
}
}
}
}
if (prevChildren != newChildren) {
entity = convertAndSetWithValue((BeanProperty<T, Object>) association.getProperty(), entity, newChildren);
}
return entity;
} else {
BeanProperty<T, Object> property = (BeanProperty<T, Object>) association.getProperty();
Object innerEntity = property.get(entity);
Object newInnerEntity = afterCascadedMany(innerEntity, associations.subList(1, associations.size()), prevChildren, newChildren);
if (newInnerEntity != innerEntity) {
innerEntity = convertAndSetWithValue(property, entity, newInnerEntity);
}
return (T) innerEntity;
}
}
use of io.micronaut.data.model.PersistentAssociationPath in project micronaut-data by micronaut-projects.
the class AbstractCascadeOperations method cascade.
/**
* Cascade on the entity instance and collect cascade operations.
*
* @param annotationMetadata The annotationMetadata
* @param repositoryType The repositoryType
* @param fkOnly Is FK only
* @param cascadeType The cascadeType
* @param ctx The cascade context
* @param persistentEntity The persistent entity
* @param entity The entity instance
* @param cascadeOps The cascade operations
* @param <T> The entity type
*/
protected <T> void cascade(AnnotationMetadata annotationMetadata, Class<?> repositoryType, boolean fkOnly, Relation.Cascade cascadeType, CascadeContext ctx, RuntimePersistentEntity<T> persistentEntity, T entity, List<CascadeOp> cascadeOps) {
for (RuntimeAssociation<T> association : persistentEntity.getAssociations()) {
BeanProperty<T, Object> beanProperty = (BeanProperty<T, Object>) association.getProperty();
Object child = beanProperty.get(entity);
if (child == null) {
continue;
}
if (association instanceof Embedded) {
cascade(annotationMetadata, repositoryType, fkOnly, cascadeType, ctx.embedded(association), (RuntimePersistentEntity) association.getAssociatedEntity(), child, cascadeOps);
continue;
}
if (association.doesCascade(cascadeType) && (fkOnly || !association.isForeignKey())) {
if (association.getInverseSide().map(assoc -> ctx.rootAssociations.contains(assoc) || ctx.associations.contains(assoc)).orElse(false)) {
continue;
}
final RuntimePersistentEntity<Object> associatedEntity = (RuntimePersistentEntity<Object>) association.getAssociatedEntity();
switch(association.getKind()) {
case ONE_TO_ONE:
case MANY_TO_ONE:
cascadeOps.add(new CascadeOneOp(annotationMetadata, repositoryType, ctx.relation(association), cascadeType, associatedEntity, child));
continue;
case ONE_TO_MANY:
case MANY_TO_MANY:
final PersistentAssociationPath inverse = association.getInversePathSide().orElse(null);
Iterable<Object> children = (Iterable<Object>) association.getProperty().get(entity);
if (children == null || !children.iterator().hasNext()) {
continue;
}
if (inverse != null && inverse.getAssociation().getKind() == Relation.Kind.MANY_TO_ONE) {
List<Object> entities = new ArrayList<>(CollectionUtils.iterableToList(children));
for (ListIterator<Object> iterator = entities.listIterator(); iterator.hasNext(); ) {
Object c = iterator.next();
Object newC = inverse.setPropertyValue(c, entity);
if (c != newC) {
iterator.set(newC);
}
}
children = entities;
}
cascadeOps.add(new CascadeManyOp(annotationMetadata, repositoryType, ctx.relation(association), cascadeType, associatedEntity, children));
continue;
default:
throw new IllegalArgumentException("Cannot cascade for relation: " + association.getKind());
}
}
}
}
Aggregations