8787import org .springframework .data .neo4j .core .mapping .SpringDataCypherDsl ;
8888import org .springframework .data .neo4j .core .mapping .callback .EventSupport ;
8989import org .springframework .data .neo4j .core .schema .TargetNode ;
90+ import org .springframework .data .neo4j .core .support .UserDefinedChangeEvaluator ;
91+ import org .springframework .data .neo4j .core .support .UserDefinedChangeSupport ;
9092import org .springframework .data .neo4j .core .transaction .Neo4jTransactionManager ;
9193import org .springframework .data .neo4j .repository .NoResultException ;
9294import org .springframework .data .neo4j .repository .query .QueryFragments ;
@@ -156,6 +158,7 @@ public boolean isReadOnly() {
156158
157159 @ Nullable
158160 private TransactionTemplate transactionTemplateReadOnly ;
161+ private final Map <Class , UserDefinedChangeEvaluator > userDefinedChangeEvaluators = new HashMap <>();
159162
160163 public Neo4jTemplate (Neo4jClient neo4jClient ) {
161164 this (neo4jClient , new Neo4jMappingContext ());
@@ -452,7 +455,9 @@ public <T> T save(T instance) {
452455 private <T > T saveImpl (T instance , @ Nullable Collection <PropertyFilter .ProjectedPath > includedProperties ,
453456 @ Nullable NestedRelationshipProcessingStateMachine stateMachine ) {
454457
455- if (stateMachine != null && stateMachine .hasProcessedValue (instance )) {
458+ if ((stateMachine != null && stateMachine .hasProcessedValue (instance ))
459+ || (instance instanceof UserDefinedChangeSupport udcs && !udcs .needsUpdate ())
460+ || (this .userDefinedChangeEvaluators .containsKey (instance .getClass ()) && !this .userDefinedChangeEvaluators .get (instance .getClass ()).needsUpdate (instance ))) {
456461 return instance ;
457462 }
458463
@@ -977,11 +982,26 @@ private <T> T processNestedRelations(Neo4jPersistentEntity<?> sourceEntity,
977982 .identifyAndExtractRelationshipTargetNode (relatedValueToStore );
978983 Neo4jPersistentEntity <?> targetEntity = this .neo4jMappingContext
979984 .getRequiredPersistentEntity (relatedObjectBeforeCallbacksApplied .getClass ());
980- boolean isNewEntity = targetEntity .isNew (relatedObjectBeforeCallbacksApplied );
985+ var isNewEntity = targetEntity .isNew (relatedObjectBeforeCallbacksApplied );
986+ var skipUpdateOfEntity = false ;
987+ if (relatedValueToStore instanceof UserDefinedChangeSupport udcs ) {
988+ skipUpdateOfEntity = !isNewEntity && !udcs .needsUpdate ();
989+ }
990+ if (relatedValueToStore instanceof MappingSupport .RelationshipPropertiesWithEntityHolder rpweh ) {
991+ var relatedEntity = rpweh .getRelatedEntity ();
992+ if (relatedEntity instanceof UserDefinedChangeSupport udcs ) {
993+ skipUpdateOfEntity = !isNewEntity && !udcs .needsUpdate ();
994+ }
995+ }
996+ else if (!skipUpdateOfEntity ) {
997+ skipUpdateOfEntity = this .userDefinedChangeEvaluators .containsKey (relatedValueToStore .getClass ());
998+ }
981999
9821000 Object newRelatedObject = stateMachine .hasProcessedValue (relatedObjectBeforeCallbacksApplied )
9831001 ? stateMachine .getProcessedAs (relatedObjectBeforeCallbacksApplied )
984- : this .eventSupport .maybeCallBeforeBind (relatedObjectBeforeCallbacksApplied );
1002+ : skipUpdateOfEntity
1003+ ? relatedObjectBeforeCallbacksApplied
1004+ : this .eventSupport .maybeCallBeforeBind (relatedObjectBeforeCallbacksApplied );
9851005
9861006 Object relatedInternalId ;
9871007 Entity savedEntity = null ;
@@ -990,7 +1010,7 @@ private <T> T processNestedRelations(Neo4jPersistentEntity<?> sourceEntity,
9901010 relatedInternalId = stateMachine .getObjectId (relatedValueToStore );
9911011 }
9921012 else {
993- if (isNewEntity || relationshipDescription .cascadeUpdates ()) {
1013+ if (( isNewEntity || relationshipDescription .cascadeUpdates ()) && ! skipUpdateOfEntity ) {
9941014 savedEntity = saveRelatedNode (newRelatedObject , targetEntity , includeProperty ,
9951015 currentPropertyPath );
9961016 }
@@ -1101,7 +1121,9 @@ else if (relationshipDescription.hasRelationshipProperties() && fromId != null)
11011121 else {
11021122 if (isNewRelationship && idProperty != null ) {
11031123 newRelationshipPropertiesRows .add (properties );
1104- newRelationshipPropertiesToStore .add (relatedValueToStore );
1124+ if (!skipUpdateOfEntity ) {
1125+ newRelationshipPropertiesToStore .add (relatedValueToStore );
1126+ }
11051127 }
11061128 else {
11071129 this .neo4jMappingContext .getEntityConverter ()
@@ -1325,6 +1347,8 @@ public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
13251347 }
13261348 }
13271349 setTransactionManager (transactionManager );
1350+ this .userDefinedChangeEvaluators .putAll (beanFactory .getBeanProvider (UserDefinedChangeEvaluator .class ).stream ()
1351+ .collect (Collectors .toMap (e -> e .getEvaluatingClass (), e -> e )));
13281352 }
13291353
13301354 // only used for the CDI configuration
0 commit comments