@@ -799,6 +799,11 @@ private <T> T processNestedRelations(
799
799
Neo4jPersistentProperty relationshipProperty = association .getInverse ();
800
800
801
801
RelationshipHandler relationshipHandler = RelationshipHandler .forProperty (relationshipProperty , rawValue );
802
+ List <Object > plainRelationshipRows = new ArrayList <>();
803
+ List <Map <String , Object >> relationshipPropertiesRows = new ArrayList <>();
804
+ List <Map <String , Object >> newRelationshipPropertiesRows = new ArrayList <>();
805
+ List <Object > updateRelatedValuesToStore = new ArrayList <>();
806
+ List <Object > newRelatedValuesToStore = new ArrayList <>();
802
807
803
808
for (Object relatedValueToStore : relatedValuesToStore ) {
804
809
@@ -847,28 +852,60 @@ private <T> T processNestedRelations(
847
852
848
853
Object idValue = idProperty != null
849
854
? relationshipContext
850
- .getRelationshipPropertiesPropertyAccessor (relatedValueToStore ).getProperty (idProperty )
855
+ .getRelationshipPropertiesPropertyAccessor (relatedValueToStore ).getProperty (idProperty )
851
856
: null ;
852
857
858
+ Map <String , Object > properties = new HashMap <>();
859
+ properties .put (Constants .FROM_ID_PARAMETER_NAME , convertIdValues (sourceEntity .getRequiredIdProperty (), fromId ));
860
+ properties .put (Constants .TO_ID_PARAMETER_NAME , relatedInternalId );
861
+ properties .put (Constants .NAME_OF_KNOWN_RELATIONSHIP_PARAM , idValue );
853
862
boolean isNewRelationship = idValue == null ;
854
-
855
- CreateRelationshipStatementHolder statementHolder = neo4jMappingContext .createStatement (
856
- sourceEntity , relationshipContext , relatedValueToStore , isNewRelationship );
857
-
858
- Optional <Long > relationshipInternalId = neo4jClient .query (renderer .render (statementHolder .getStatement ()))
859
- .bind (convertIdValues (sourceEntity .getRequiredIdProperty (), fromId )) //
860
- .to (Constants .FROM_ID_PARAMETER_NAME ) //
861
- .bind (relatedInternalId ) //
862
- .to (Constants .TO_ID_PARAMETER_NAME ) //
863
- .bind (idValue ) //
864
- .to (Constants .NAME_OF_KNOWN_RELATIONSHIP_PARAM ) //
865
- .bindAll (statementHolder .getProperties ())
866
- .fetchAs (Long .class ).one ();
867
-
868
- if (idProperty != null && isNewRelationship ) {
869
- relationshipContext
870
- .getRelationshipPropertiesPropertyAccessor (relatedValueToStore )
871
- .setProperty (idProperty , relationshipInternalId .get ());
863
+ if (relationshipDescription .isDynamic ()) {
864
+ // create new dynamic relationship properties
865
+ if (relationshipDescription .hasRelationshipProperties () && isNewRelationship && idProperty != null ) {
866
+ CreateRelationshipStatementHolder statementHolder = neo4jMappingContext .createStatementForSingleRelationship (
867
+ sourceEntity , relationshipDescription , relatedValueToStore , true );
868
+
869
+ List <Object > row = Collections .singletonList (properties );
870
+ statementHolder = statementHolder .addProperty (Constants .NAME_OF_RELATIONSHIP_LIST_PARAM , row );
871
+ Optional <Long > relationshipInternalId = neo4jClient .query (renderer .render (statementHolder .getStatement ()))
872
+ .bind (convertIdValues (sourceEntity .getRequiredIdProperty (), fromId )) //
873
+ .to (Constants .FROM_ID_PARAMETER_NAME ) //
874
+ .bind (relatedInternalId ) //
875
+ .to (Constants .TO_ID_PARAMETER_NAME ) //
876
+ .bind (idValue ) // always null
877
+ .to (Constants .NAME_OF_KNOWN_RELATIONSHIP_PARAM ) //
878
+ .bindAll (statementHolder .getProperties ())
879
+ .fetchAs (Long .class ).one ();
880
+ assignIdToRelationshipProperties (relationshipContext , relatedValueToStore , idProperty , relationshipInternalId .get ());
881
+ } else { // plain (new or to update) dynamic relationship or dynamic relationships with properties to update
882
+ CreateRelationshipStatementHolder statementHolder = neo4jMappingContext .createStatementForSingleRelationship (
883
+ sourceEntity , relationshipDescription , relatedValueToStore , false );
884
+
885
+ List <Object > row = Collections .singletonList (properties );
886
+ statementHolder = statementHolder .addProperty (Constants .NAME_OF_RELATIONSHIP_LIST_PARAM , row );
887
+ neo4jClient .query (renderer .render (statementHolder .getStatement ()))
888
+ .bind (convertIdValues (sourceEntity .getRequiredIdProperty (), fromId )) //
889
+ .to (Constants .FROM_ID_PARAMETER_NAME ) //
890
+ .bind (relatedInternalId ) //
891
+ .to (Constants .TO_ID_PARAMETER_NAME ) //
892
+ .bind (idValue )
893
+ .to (Constants .NAME_OF_KNOWN_RELATIONSHIP_PARAM ) //
894
+ .bindAll (statementHolder .getProperties ())
895
+ .run ();
896
+ }
897
+ } else if (relationshipDescription .hasRelationshipProperties () && isNewRelationship && idProperty != null ) {
898
+ newRelationshipPropertiesRows .add (properties );
899
+ newRelatedValuesToStore .add (relatedValueToStore );
900
+ } else if (relationshipDescription .hasRelationshipProperties ()) {
901
+ neo4jMappingContext .getEntityConverter ().write (
902
+ ((MappingSupport .RelationshipPropertiesWithEntityHolder ) relatedValueToStore ).getRelationshipProperties (),
903
+ properties );
904
+
905
+ relationshipPropertiesRows .add (properties );
906
+ } else {
907
+ // non-dynamic relationship or relationship with properties
908
+ plainRelationshipRows .add (properties );
872
909
}
873
910
874
911
if (processState != ProcessState .PROCESSED_ALL_VALUES ) {
@@ -883,6 +920,37 @@ private <T> T processNestedRelations(
883
920
884
921
relationshipHandler .handle (relatedValueToStore , relatedObjectBeforeCallbacksApplied , potentiallyRecreatedNewRelatedObject );
885
922
}
923
+ // batch operations
924
+ if (!(relationshipDescription .hasRelationshipProperties () || relationshipDescription .isDynamic () || plainRelationshipRows .isEmpty ())) {
925
+ CreateRelationshipStatementHolder statementHolder = neo4jMappingContext .createStatementForImperativeSimpleRelationshipBatch (
926
+ sourceEntity , relationshipDescription , plainRelationshipRows );
927
+ statementHolder = statementHolder .addProperty (Constants .NAME_OF_RELATIONSHIP_LIST_PARAM , plainRelationshipRows );
928
+ neo4jClient .query (renderer .render (statementHolder .getStatement ()))
929
+ .bindAll (statementHolder .getProperties ())
930
+ .run ();
931
+ } else if (relationshipDescription .hasRelationshipProperties ()) {
932
+ if (!relationshipPropertiesRows .isEmpty ()) {
933
+ CreateRelationshipStatementHolder statementHolder = neo4jMappingContext .createStatementForImperativeRelationshipsWithPropertiesBatch (false ,
934
+ sourceEntity , relationshipDescription , updateRelatedValuesToStore , relationshipPropertiesRows );
935
+ statementHolder = statementHolder .addProperty (Constants .NAME_OF_RELATIONSHIP_LIST_PARAM , relationshipPropertiesRows );
936
+
937
+ neo4jClient .query (renderer .render (statementHolder .getStatement ()))
938
+ .bindAll (statementHolder .getProperties ())
939
+ .run ();
940
+ } else if (!newRelatedValuesToStore .isEmpty ()) {
941
+ CreateRelationshipStatementHolder statementHolder = neo4jMappingContext .createStatementForImperativeRelationshipsWithPropertiesBatch (true ,
942
+ sourceEntity , relationshipDescription , newRelatedValuesToStore , newRelationshipPropertiesRows );
943
+
944
+ List <Long > all = new ArrayList <>(neo4jClient .query (renderer .render (statementHolder .getStatement ()))
945
+ .bindAll (statementHolder .getProperties ())
946
+ .fetchAs (Long .class ).all ());
947
+ // assign new ids
948
+ for (int i = 0 ; i < all .size (); i ++) {
949
+ Long aLong = all .get (i );
950
+ assignIdToRelationshipProperties (relationshipContext , newRelatedValuesToStore .get (i ), idProperty , aLong );
951
+ }
952
+ }
953
+ }
886
954
887
955
relationshipHandler .applyFinalResultToOwner (propertyAccessor );
888
956
});
@@ -892,6 +960,12 @@ private <T> T processNestedRelations(
892
960
return finalSubgraphRoot ;
893
961
}
894
962
963
+ private void assignIdToRelationshipProperties (NestedRelationshipContext relationshipContext , Object relatedValueToStore , Neo4jPersistentProperty idProperty , Long relationshipInternalId ) {
964
+ relationshipContext
965
+ .getRelationshipPropertiesPropertyAccessor (relatedValueToStore )
966
+ .setProperty (idProperty , relationshipInternalId );
967
+ }
968
+
895
969
private Entity saveRelatedNode (Object entity , NodeDescription <?> targetNodeDescription , PropertyFilter includeProperty , PropertyFilter .RelaxedPropertyPath currentPropertyPath ) {
896
970
897
971
DynamicLabels dynamicLabels = determineDynamicLabels (entity , (Neo4jPersistentEntity <?>) targetNodeDescription );
0 commit comments