@@ -770,6 +770,11 @@ private <T> T processNestedRelations(
770
770
Neo4jPersistentProperty relationshipProperty = association .getInverse ();
771
771
772
772
RelationshipHandler relationshipHandler = RelationshipHandler .forProperty (relationshipProperty , rawValue );
773
+ List <Object > plainRelationshipRows = new ArrayList <>();
774
+ List <Map <String , Object >> relationshipPropertiesRows = new ArrayList <>();
775
+ List <Map <String , Object >> newRelationshipPropertiesRows = new ArrayList <>();
776
+ List <Object > updateRelatedValuesToStore = new ArrayList <>();
777
+ List <Object > newRelatedValuesToStore = new ArrayList <>();
773
778
774
779
for (Object relatedValueToStore : relatedValuesToStore ) {
775
780
@@ -818,28 +823,60 @@ private <T> T processNestedRelations(
818
823
819
824
Object idValue = idProperty != null
820
825
? relationshipContext
821
- .getRelationshipPropertiesPropertyAccessor (relatedValueToStore ).getProperty (idProperty )
826
+ .getRelationshipPropertiesPropertyAccessor (relatedValueToStore ).getProperty (idProperty )
822
827
: null ;
823
828
829
+ Map <String , Object > properties = new HashMap <>();
830
+ properties .put (Constants .FROM_ID_PARAMETER_NAME , convertIdValues (sourceEntity .getRequiredIdProperty (), fromId ));
831
+ properties .put (Constants .TO_ID_PARAMETER_NAME , relatedInternalId );
832
+ properties .put (Constants .NAME_OF_KNOWN_RELATIONSHIP_PARAM , idValue );
824
833
boolean isNewRelationship = idValue == null ;
825
-
826
- CreateRelationshipStatementHolder statementHolder = neo4jMappingContext .createStatement (
827
- sourceEntity , relationshipContext , relatedValueToStore , isNewRelationship );
828
-
829
- Optional <Long > relationshipInternalId = neo4jClient .query (renderer .render (statementHolder .getStatement ()))
830
- .bind (convertIdValues (sourceEntity .getRequiredIdProperty (), fromId )) //
831
- .to (Constants .FROM_ID_PARAMETER_NAME ) //
832
- .bind (relatedInternalId ) //
833
- .to (Constants .TO_ID_PARAMETER_NAME ) //
834
- .bind (idValue ) //
835
- .to (Constants .NAME_OF_KNOWN_RELATIONSHIP_PARAM ) //
836
- .bindAll (statementHolder .getProperties ())
837
- .fetchAs (Long .class ).one ();
838
-
839
- if (idProperty != null && isNewRelationship ) {
840
- relationshipContext
841
- .getRelationshipPropertiesPropertyAccessor (relatedValueToStore )
842
- .setProperty (idProperty , relationshipInternalId .get ());
834
+ if (relationshipDescription .isDynamic ()) {
835
+ // create new dynamic relationship properties
836
+ if (relationshipDescription .hasRelationshipProperties () && isNewRelationship && idProperty != null ) {
837
+ CreateRelationshipStatementHolder statementHolder = neo4jMappingContext .createStatementForSingleRelationship (
838
+ sourceEntity , relationshipDescription , relatedValueToStore , true );
839
+
840
+ List <Object > row = Collections .singletonList (properties );
841
+ statementHolder = statementHolder .addProperty (Constants .NAME_OF_RELATIONSHIP_LIST_PARAM , row );
842
+ Optional <Long > relationshipInternalId = neo4jClient .query (renderer .render (statementHolder .getStatement ()))
843
+ .bind (convertIdValues (sourceEntity .getRequiredIdProperty (), fromId )) //
844
+ .to (Constants .FROM_ID_PARAMETER_NAME ) //
845
+ .bind (relatedInternalId ) //
846
+ .to (Constants .TO_ID_PARAMETER_NAME ) //
847
+ .bind (idValue ) // always null
848
+ .to (Constants .NAME_OF_KNOWN_RELATIONSHIP_PARAM ) //
849
+ .bindAll (statementHolder .getProperties ())
850
+ .fetchAs (Long .class ).one ();
851
+ assignIdToRelationshipProperties (relationshipContext , relatedValueToStore , idProperty , relationshipInternalId .get ());
852
+ } else { // plain (new or to update) dynamic relationship or dynamic relationships with properties to update
853
+ CreateRelationshipStatementHolder statementHolder = neo4jMappingContext .createStatementForSingleRelationship (
854
+ sourceEntity , relationshipDescription , relatedValueToStore , false );
855
+
856
+ List <Object > row = Collections .singletonList (properties );
857
+ statementHolder = statementHolder .addProperty (Constants .NAME_OF_RELATIONSHIP_LIST_PARAM , row );
858
+ 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
+ .run ();
867
+ }
868
+ } else if (relationshipDescription .hasRelationshipProperties () && isNewRelationship && idProperty != null ) {
869
+ newRelationshipPropertiesRows .add (properties );
870
+ newRelatedValuesToStore .add (relatedValueToStore );
871
+ } else if (relationshipDescription .hasRelationshipProperties ()) {
872
+ neo4jMappingContext .getEntityConverter ().write (
873
+ ((MappingSupport .RelationshipPropertiesWithEntityHolder ) relatedValueToStore ).getRelationshipProperties (),
874
+ properties );
875
+
876
+ relationshipPropertiesRows .add (properties );
877
+ } else {
878
+ // non-dynamic relationship or relationship with properties
879
+ plainRelationshipRows .add (properties );
843
880
}
844
881
845
882
if (processState != ProcessState .PROCESSED_ALL_VALUES ) {
@@ -854,6 +891,37 @@ private <T> T processNestedRelations(
854
891
855
892
relationshipHandler .handle (relatedValueToStore , relatedObjectBeforeCallbacksApplied , potentiallyRecreatedNewRelatedObject );
856
893
}
894
+ // batch operations
895
+ if (!(relationshipDescription .hasRelationshipProperties () || relationshipDescription .isDynamic () || plainRelationshipRows .isEmpty ())) {
896
+ CreateRelationshipStatementHolder statementHolder = neo4jMappingContext .createStatementForImperativeSimpleRelationshipBatch (
897
+ sourceEntity , relationshipDescription , plainRelationshipRows );
898
+ statementHolder = statementHolder .addProperty (Constants .NAME_OF_RELATIONSHIP_LIST_PARAM , plainRelationshipRows );
899
+ neo4jClient .query (renderer .render (statementHolder .getStatement ()))
900
+ .bindAll (statementHolder .getProperties ())
901
+ .run ();
902
+ } else if (relationshipDescription .hasRelationshipProperties ()) {
903
+ if (!relationshipPropertiesRows .isEmpty ()) {
904
+ CreateRelationshipStatementHolder statementHolder = neo4jMappingContext .createStatementForImperativeRelationshipsWithPropertiesBatch (false ,
905
+ sourceEntity , relationshipDescription , updateRelatedValuesToStore , relationshipPropertiesRows );
906
+ statementHolder = statementHolder .addProperty (Constants .NAME_OF_RELATIONSHIP_LIST_PARAM , relationshipPropertiesRows );
907
+
908
+ neo4jClient .query (renderer .render (statementHolder .getStatement ()))
909
+ .bindAll (statementHolder .getProperties ())
910
+ .run ();
911
+ } else if (!newRelatedValuesToStore .isEmpty ()) {
912
+ CreateRelationshipStatementHolder statementHolder = neo4jMappingContext .createStatementForImperativeRelationshipsWithPropertiesBatch (true ,
913
+ sourceEntity , relationshipDescription , newRelatedValuesToStore , newRelationshipPropertiesRows );
914
+
915
+ List <Long > all = new ArrayList <>(neo4jClient .query (renderer .render (statementHolder .getStatement ()))
916
+ .bindAll (statementHolder .getProperties ())
917
+ .fetchAs (Long .class ).all ());
918
+ // assign new ids
919
+ for (int i = 0 ; i < all .size (); i ++) {
920
+ Long aLong = all .get (i );
921
+ assignIdToRelationshipProperties (relationshipContext , newRelatedValuesToStore .get (i ), idProperty , aLong );
922
+ }
923
+ }
924
+ }
857
925
858
926
relationshipHandler .applyFinalResultToOwner (propertyAccessor );
859
927
});
@@ -863,6 +931,12 @@ private <T> T processNestedRelations(
863
931
return finalSubgraphRoot ;
864
932
}
865
933
934
+ private void assignIdToRelationshipProperties (NestedRelationshipContext relationshipContext , Object relatedValueToStore , Neo4jPersistentProperty idProperty , Long relationshipInternalId ) {
935
+ relationshipContext
936
+ .getRelationshipPropertiesPropertyAccessor (relatedValueToStore )
937
+ .setProperty (idProperty , relationshipInternalId );
938
+ }
939
+
866
940
private Entity saveRelatedNode (Object entity , NodeDescription <?> targetNodeDescription , PropertyFilter includeProperty , PropertyFilter .RelaxedPropertyPath currentPropertyPath ) {
867
941
868
942
DynamicLabels dynamicLabels = determineDynamicLabels (entity , (Neo4jPersistentEntity <?>) targetNodeDescription );
0 commit comments