Skip to content

Allow dynamic projection for Neo4jTemplate::save #2420

@Andy2003

Description

@Andy2003

There are situations when you want to dynamically determine which fields of a domain object should actually be saved.

To achieve this it would be good to have a method similar to Neo4jTemplate::saveImpl available as a public API

private <T> T saveImpl(T instance, @Nullable Map<PropertyPath, Boolean> includedProperties, @Nullable NestedRelationshipProcessingStateMachine stateMachine) {
if (stateMachine != null && stateMachine.hasProcessedValue(instance)) {
return instance;
}
Neo4jPersistentEntity<?> entityMetaData = neo4jMappingContext.getRequiredPersistentEntity(instance.getClass());
boolean isEntityNew = entityMetaData.isNew(instance);
T entityToBeSaved = eventSupport.maybeCallBeforeBind(instance);
DynamicLabels dynamicLabels = determineDynamicLabels(entityToBeSaved, entityMetaData);
@SuppressWarnings("unchecked") // Applies to retrieving the meta data
TemplateSupport.FilteredBinderFunction<T> binderFunction = TemplateSupport.createAndApplyPropertyFilter(
includedProperties, entityMetaData,
neo4jMappingContext.getRequiredBinderFunctionFor((Class<T>) entityToBeSaved.getClass())
);
Optional<Entity> newOrUpdatedNode = neo4jClient
.query(() -> renderer.render(cypherGenerator.prepareSaveOf(entityMetaData, dynamicLabels)))
.bind(entityToBeSaved)
.with(binderFunction)
.fetchAs(Entity.class)
.one();
if (!newOrUpdatedNode.isPresent()) {
if (entityMetaData.hasVersionProperty()) {
throw new OptimisticLockingFailureException(OPTIMISTIC_LOCKING_ERROR_MESSAGE);
}
// defensive exception throwing
throw new IllegalStateException("Could not retrieve an internal id while saving.");
}
Long internalId = newOrUpdatedNode.get().id();
PersistentPropertyAccessor<T> propertyAccessor = entityMetaData.getPropertyAccessor(entityToBeSaved);
if (entityMetaData.isUsingInternalIds()) {
propertyAccessor.setProperty(entityMetaData.getRequiredIdProperty(), internalId);
}
TemplateSupport.updateVersionPropertyIfPossible(entityMetaData, propertyAccessor, newOrUpdatedNode.get());
if (stateMachine == null) {
stateMachine = new NestedRelationshipProcessingStateMachine(neo4jMappingContext, instance, internalId);
}
stateMachine.markValueAsProcessed(instance, internalId);
processRelations(entityMetaData, propertyAccessor, isEntityNew, stateMachine, binderFunction.filter);
T bean = propertyAccessor.getBean();
stateMachine.markValueAsProcessedAs(instance, bean);
return bean;
}

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions