Skip to content

Commit f5674af

Browse files
committed
GH-2809 - Find the right id/element id function for assignedIds.
* Avoid using the outdated id function wherever possible. * Never fall back to `toString(id((element))` (in Neo4j 4.4 scenarios) Closes #2809
1 parent 2b73bde commit f5674af

File tree

7 files changed

+75
-61
lines changed

7 files changed

+75
-61
lines changed

src/main/java/org/springframework/data/neo4j/core/Neo4jTemplate.java

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ private <T> T saveImpl(T instance, @Nullable Collection<PropertyFilter.Projected
401401
neo4jMappingContext.getRequiredBinderFunctionFor((Class<T>) entityToBeSaved.getClass())
402402
);
403403
Optional<Entity> newOrUpdatedNode = neo4jClient
404-
.query(() -> renderer.render(cypherGenerator.prepareSaveOf(entityMetaData, dynamicLabels)))
404+
.query(() -> renderer.render(cypherGenerator.prepareSaveOf(entityMetaData, dynamicLabels, TemplateSupport.rendererRendersElementId(renderer))))
405405
.bind(entityToBeSaved)
406406
.with(binderFunction)
407407
.fetchAs(Entity.class)
@@ -416,7 +416,7 @@ private <T> T saveImpl(T instance, @Nullable Collection<PropertyFilter.Projected
416416
}
417417

418418
Object elementId = newOrUpdatedNode.map(node -> {
419-
if (!entityMetaData.isUsingDeprecatedInternalId() && entityMetaData.isUsingInternalIds()) {
419+
if (!entityMetaData.isUsingDeprecatedInternalId() && TemplateSupport.rendererRendersElementId(renderer)) {
420420
return IdentitySupport.getElementId(node);
421421
}
422422
return node.id();
@@ -764,6 +764,7 @@ private <T> T processNestedRelations(
764764
// Remove all relationships before creating all new if the entity is not new and the relationship
765765
// has not been processed before.
766766
// This avoids the usage of cache but might have significant impact on overall performance
767+
boolean canUseElementId = TemplateSupport.rendererRendersElementId(renderer);
767768
if (!isParentObjectNew && !stateMachine.hasProcessedRelationship(fromId, relationshipDescription)) {
768769

769770
List<Object> knownRelationshipsIds = new ArrayList<>();
@@ -780,7 +781,7 @@ private <T> T processNestedRelations(
780781
}
781782
}
782783

783-
Statement relationshipRemoveQuery = cypherGenerator.prepareDeleteOf(sourceEntity, relationshipDescription);
784+
Statement relationshipRemoveQuery = cypherGenerator.prepareDeleteOf(sourceEntity, relationshipDescription, canUseElementId);
784785

785786
neo4jClient.query(renderer.render(relationshipRemoveQuery))
786787
.bind(convertIdValues(sourceEntity.getIdProperty(), fromId)) //
@@ -858,7 +859,7 @@ private <T> T processNestedRelations(
858859
// create new dynamic relationship properties
859860
if (relationshipDescription.hasRelationshipProperties() && isNewRelationship && idProperty != null) {
860861
CreateRelationshipStatementHolder statementHolder = neo4jMappingContext.createStatementForSingleRelationship(
861-
sourceEntity, relationshipDescription, relatedValueToStore, true);
862+
sourceEntity, relationshipDescription, relatedValueToStore, true, canUseElementId);
862863

863864
List<Object> row = Collections.singletonList(properties);
864865
statementHolder = statementHolder.addProperty(Constants.NAME_OF_RELATIONSHIP_LIST_PARAM, row);
@@ -879,7 +880,7 @@ private <T> T processNestedRelations(
879880
} else { // plain (new or to update) dynamic relationship or dynamic relationships with properties to update
880881

881882
CreateRelationshipStatementHolder statementHolder = neo4jMappingContext.createStatementForSingleRelationship(
882-
sourceEntity, relationshipDescription, relatedValueToStore, false);
883+
sourceEntity, relationshipDescription, relatedValueToStore, false, canUseElementId);
883884

884885
List<Object> row = Collections.singletonList(properties);
885886
statementHolder = statementHolder.addProperty(Constants.NAME_OF_RELATIONSHIP_LIST_PARAM, row);
@@ -921,15 +922,15 @@ private <T> T processNestedRelations(
921922
// batch operations
922923
if (!(relationshipDescription.hasRelationshipProperties() || relationshipDescription.isDynamic() || plainRelationshipRows.isEmpty())) {
923924
CreateRelationshipStatementHolder statementHolder = neo4jMappingContext.createStatementForImperativeSimpleRelationshipBatch(
924-
sourceEntity, relationshipDescription, plainRelationshipRows);
925+
sourceEntity, relationshipDescription, plainRelationshipRows, canUseElementId);
925926
statementHolder = statementHolder.addProperty(Constants.NAME_OF_RELATIONSHIP_LIST_PARAM, plainRelationshipRows);
926927
neo4jClient.query(renderer.render(statementHolder.getStatement()))
927928
.bindAll(statementHolder.getProperties())
928929
.run();
929930
} else if (relationshipDescription.hasRelationshipProperties()) {
930931
if (!relationshipPropertiesRows.isEmpty()) {
931932
CreateRelationshipStatementHolder statementHolder = neo4jMappingContext.createStatementForImperativeRelationshipsWithPropertiesBatch(false,
932-
sourceEntity, relationshipDescription, updateRelatedValuesToStore, relationshipPropertiesRows);
933+
sourceEntity, relationshipDescription, updateRelatedValuesToStore, relationshipPropertiesRows, canUseElementId);
933934
statementHolder = statementHolder.addProperty(Constants.NAME_OF_RELATIONSHIP_LIST_PARAM, relationshipPropertiesRows);
934935

935936
neo4jClient.query(renderer.render(statementHolder.getStatement()))
@@ -938,7 +939,7 @@ private <T> T processNestedRelations(
938939
}
939940
if (!newRelatedValuesToStore.isEmpty()) {
940941
CreateRelationshipStatementHolder statementHolder = neo4jMappingContext.createStatementForImperativeRelationshipsWithPropertiesBatch(true,
941-
sourceEntity, relationshipDescription, newRelatedValuesToStore, newRelationshipPropertiesRows);
942+
sourceEntity, relationshipDescription, newRelatedValuesToStore, newRelationshipPropertiesRows, canUseElementId);
942943
List<Object> all = new ArrayList<>(neo4jClient.query(renderer.render(statementHolder.getStatement()))
943944
.bindAll(statementHolder.getProperties())
944945
.fetchAs(Object.class)
@@ -996,7 +997,7 @@ private Entity saveRelatedNode(Object entity, NodeDescription<?> targetNodeDescr
996997
return tree;
997998
});
998999
Optional<Entity> optionalSavedNode = neo4jClient
999-
.query(() -> renderer.render(cypherGenerator.prepareSaveOf(targetNodeDescription, dynamicLabels)))
1000+
.query(() -> renderer.render(cypherGenerator.prepareSaveOf(targetNodeDescription, dynamicLabels, TemplateSupport.rendererRendersElementId(renderer))))
10001001
.bind(entity).with(binderFunction)
10011002
.fetchAs(Entity.class)
10021003
.one();

src/main/java/org/springframework/data/neo4j/core/ReactiveNeo4jTemplate.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,8 @@ private <T> Mono<T> saveImpl(T instance, @Nullable Collection<PropertyFilter.Pro
438438
includedProperties, entityMetaData,
439439
neo4jMappingContext.getRequiredBinderFunctionFor((Class<T>) entityToBeSaved.getClass()));
440440

441-
Mono<Entity> idMono = this.neo4jClient.query(() -> renderer.render(cypherGenerator.prepareSaveOf(entityMetaData, dynamicLabels)))
441+
boolean canUseElementId = TemplateSupport.rendererRendersElementId(renderer);
442+
Mono<Entity> idMono = this.neo4jClient.query(() -> renderer.render(cypherGenerator.prepareSaveOf(entityMetaData, dynamicLabels, canUseElementId)))
442443
.bind(entityToBeSaved)
443444
.with(binderFunction)
444445
.fetchAs(Entity.class)
@@ -452,7 +453,7 @@ private <T> Mono<T> saveImpl(T instance, @Nullable Collection<PropertyFilter.Pro
452453

453454
PersistentPropertyAccessor<T> propertyAccessor = entityMetaData.getPropertyAccessor(entityToBeSaved);
454455
return idMono.doOnNext(newOrUpdatedNode -> {
455-
var elementId = !entityMetaData.isUsingDeprecatedInternalId() && entityMetaData.isUsingInternalIds()
456+
var elementId = !entityMetaData.isUsingDeprecatedInternalId() && canUseElementId
456457
? IdentitySupport.getElementId(newOrUpdatedNode)
457458
: newOrUpdatedNode.id();
458459
TemplateSupport.setGeneratedIdIfNecessary(entityMetaData, propertyAccessor, elementId, Optional.of(newOrUpdatedNode));
@@ -901,6 +902,7 @@ private <T> Mono<T> processNestedRelations(Neo4jPersistentEntity<?> sourceEntity
901902
// Remove all relationships before creating all new if the entity is not new and the relationship
902903
// has not been processed before.
903904
// This avoids the usage of cache but might have significant impact on overall performance
905+
boolean canUseElementId = TemplateSupport.rendererRendersElementId(renderer);
904906
if (!isParentObjectNew && !stateMachine.hasProcessedRelationship(fromId, relationshipDescription)) {
905907

906908
List<Object> knownRelationshipsIds = new ArrayList<>();
@@ -919,7 +921,7 @@ private <T> Mono<T> processNestedRelations(Neo4jPersistentEntity<?> sourceEntity
919921
}
920922
}
921923

922-
Statement relationshipRemoveQuery = cypherGenerator.prepareDeleteOf(sourceEntity, relationshipDescription);
924+
Statement relationshipRemoveQuery = cypherGenerator.prepareDeleteOf(sourceEntity, relationshipDescription, canUseElementId);
923925

924926
relationshipDeleteMonos.add(
925927
neo4jClient.query(renderer.render(relationshipRemoveQuery))
@@ -990,7 +992,7 @@ private <T> Mono<T> processNestedRelations(Neo4jPersistentEntity<?> sourceEntity
990992

991993
boolean isNewRelationship = idValue == null;
992994
CreateRelationshipStatementHolder statementHolder = neo4jMappingContext.createStatementForSingleRelationship(
993-
sourceEntity, relationshipDescription, relatedValueToStore, isNewRelationship);
995+
sourceEntity, relationshipDescription, relatedValueToStore, isNewRelationship, canUseElementId);
994996

995997
Map<String, Object> properties = new HashMap<>();
996998
properties.put(Constants.FROM_ID_PARAMETER_NAME, convertIdValues(sourceEntity.getRequiredIdProperty(), fromId));
@@ -1086,7 +1088,7 @@ private Mono<Entity> saveRelatedNode(Object relatedNode, Neo4jPersistentEntity<?
10861088
return tree;
10871089
});
10881090
return neo4jClient
1089-
.query(() -> renderer.render(cypherGenerator.prepareSaveOf(targetNodeDescription, dynamicLabels)))
1091+
.query(() -> renderer.render(cypherGenerator.prepareSaveOf(targetNodeDescription, dynamicLabels, TemplateSupport.rendererRendersElementId(renderer))))
10901092
.bind(entity).with(binderFunction)
10911093
.fetchAs(Entity.class)
10921094
.one();

src/main/java/org/springframework/data/neo4j/core/TemplateSupport.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -427,10 +427,10 @@ static <T> Object retrieveOrSetRelatedId(
427427
* @return {@literal true} if renderer will use elementId
428428
*/
429429
static boolean rendererCanUseElementIdIfPresent(Renderer renderer, Neo4jPersistentEntity<?> targetEntity) {
430-
return !targetEntity.isUsingDeprecatedInternalId() && targetEntity.isUsingInternalIds() && rendererRendersElementId(renderer);
430+
return !targetEntity.isUsingDeprecatedInternalId() && rendererRendersElementId(renderer);
431431
}
432432

433-
private static boolean rendererRendersElementId(Renderer renderer) {
433+
static boolean rendererRendersElementId(Renderer renderer) {
434434
return renderer.render(Cypher.returning(Functions.elementId(Cypher.anyNode("n"))).build())
435435
.equals("RETURN elementId(n)");
436436
}

0 commit comments

Comments
 (0)