41
41
import org .neo4j .cypherdsl .core .Node ;
42
42
import org .neo4j .cypherdsl .core .Statement ;
43
43
import org .neo4j .cypherdsl .core .renderer .Renderer ;
44
+ import org .neo4j .driver .Value ;
44
45
import org .neo4j .driver .exceptions .NoSuchRecordException ;
45
46
import org .neo4j .driver .summary .ResultSummary ;
46
47
import org .neo4j .driver .summary .SummaryCounters ;
@@ -244,15 +245,21 @@ private <T> T saveImpl(T instance, @Nullable String inDatabase) {
244
245
.with (neo4jMappingContext .getRequiredBinderFunctionFor ((Class <T >) entityToBeSaved .getClass ()))
245
246
.fetchAs (Long .class ).one ();
246
247
247
- if (entityMetaData .hasVersionProperty () && !optionalInternalId .isPresent ()) {
248
- throw new OptimisticLockingFailureException (OPTIMISTIC_LOCKING_ERROR_MESSAGE );
248
+
249
+ if (!optionalInternalId .isPresent ()) {
250
+ if (entityMetaData .hasVersionProperty ()) {
251
+ throw new OptimisticLockingFailureException (OPTIMISTIC_LOCKING_ERROR_MESSAGE );
252
+ }
253
+ // defensive exception throwing
254
+ throw new IllegalStateException ("Could not retrieve an internal id while saving." );
249
255
}
250
256
257
+ Long internalId = optionalInternalId .get ();
251
258
PersistentPropertyAccessor <T > propertyAccessor = entityMetaData .getPropertyAccessor (entityToBeSaved );
252
259
if (entityMetaData .isUsingInternalIds ()) {
253
- propertyAccessor .setProperty (entityMetaData .getRequiredIdProperty (), optionalInternalId . get () );
260
+ propertyAccessor .setProperty (entityMetaData .getRequiredIdProperty (), internalId );
254
261
}
255
- processRelations (entityMetaData , instance , propertyAccessor , inDatabase , isEntityNew );
262
+ processRelations (entityMetaData , instance , internalId , propertyAccessor , inDatabase , isEntityNew );
256
263
257
264
return propertyAccessor .getBean ();
258
265
}
@@ -452,6 +459,14 @@ private <T> ExecutableQuery<T> createExecutableQuery(Class<T> domainType, String
452
459
* @param parentPropertyAccessor The property accessor of the parent, to modify the relationships
453
460
* @param isParentObjectNew A flag if the parent was new
454
461
*/
462
+ private <T > T processRelations (Neo4jPersistentEntity <?> neo4jPersistentEntity , T originalInstance , Long internalId ,
463
+ PersistentPropertyAccessor <?> parentPropertyAccessor ,
464
+ @ Nullable String inDatabase , boolean isParentObjectNew ) {
465
+
466
+ return processNestedRelations (neo4jPersistentEntity , parentPropertyAccessor , isParentObjectNew , inDatabase ,
467
+ new NestedRelationshipProcessingStateMachine (originalInstance , internalId ));
468
+ }
469
+
455
470
private <T > T processRelations (Neo4jPersistentEntity <?> neo4jPersistentEntity , T originalInstance ,
456
471
PersistentPropertyAccessor <?> parentPropertyAccessor ,
457
472
@ Nullable String inDatabase , boolean isParentObjectNew ) {
@@ -534,22 +549,22 @@ private <T> T processNestedRelations(Neo4jPersistentEntity<?> sourceEntity, Pers
534
549
for (Object relatedValueToStore : relatedValuesToStore ) {
535
550
536
551
// here a map entry is not always anymore a dynamic association
537
- Object relatedObjectBeforeCallbacks = relationshipContext .identifyAndExtractRelationshipTargetNode (relatedValueToStore );
538
- Neo4jPersistentEntity <?> targetEntity = neo4jMappingContext .getPersistentEntity (relatedObjectBeforeCallbacks .getClass ());
539
-
540
- boolean isEntityNew = targetEntity .isNew (relatedObjectBeforeCallbacks );
552
+ Object relatedObjectBeforeCallbacksApplied = relationshipContext .identifyAndExtractRelationshipTargetNode (relatedValueToStore );
553
+ Neo4jPersistentEntity <?> targetEntity = neo4jMappingContext .getPersistentEntity (relatedObjectBeforeCallbacksApplied .getClass ());
541
554
542
- Object newRelatedObject = eventSupport .maybeCallBeforeBind (relatedObjectBeforeCallbacks );
555
+ boolean isEntityNew = targetEntity .isNew (relatedObjectBeforeCallbacksApplied );
556
+ Object newRelatedObject = stateMachine .hasProcessedValue (relatedObjectBeforeCallbacksApplied )
557
+ ? stateMachine .getProcessedAs (relatedObjectBeforeCallbacksApplied )
558
+ : eventSupport .maybeCallBeforeBind (relatedObjectBeforeCallbacksApplied );
543
559
544
560
Long relatedInternalId ;
545
561
// No need to save values if processed
546
562
if (stateMachine .hasProcessedValue (relatedValueToStore )) {
547
- Object newRelatedObjectForQuery = stateMachine .getProcessedAs (newRelatedObject );
548
- relatedInternalId = queryRelatedNode (newRelatedObjectForQuery , targetEntity , inDatabase );
563
+ relatedInternalId = stateMachine .getInternalId (relatedObjectBeforeCallbacksApplied );
549
564
} else {
550
565
relatedInternalId = saveRelatedNode (newRelatedObject , targetEntity , inDatabase );
551
566
}
552
- stateMachine .markValueAsProcessed (relatedValueToStore );
567
+ stateMachine .markValueAsProcessed (relatedValueToStore , relatedInternalId );
553
568
554
569
Object idValue = idProperty != null
555
570
? relationshipContext
@@ -581,8 +596,8 @@ private <T> T processNestedRelations(Neo4jPersistentEntity<?> sourceEntity, Pers
581
596
// if an internal id is used this must be set to link this entity in the next iteration
582
597
if (targetEntity .isUsingInternalIds ()) {
583
598
targetPropertyAccessor .setProperty (targetEntity .getRequiredIdProperty (), relatedInternalId );
584
- stateMachine .markValueAsProcessedAs (newRelatedObject , targetPropertyAccessor .getBean ());
585
599
}
600
+ stateMachine .markValueAsProcessedAs (relatedObjectBeforeCallbacksApplied , targetPropertyAccessor .getBean ());
586
601
587
602
if (processState != ProcessState .PROCESSED_ALL_VALUES ) {
588
603
processNestedRelations (targetEntity , targetPropertyAccessor , isEntityNew , inDatabase , stateMachine );
@@ -594,7 +609,7 @@ private <T> T processNestedRelations(Neo4jPersistentEntity<?> sourceEntity, Pers
594
609
relatedValueToStore ,
595
610
targetPropertyAccessor );
596
611
597
- relationshipHandler .handle (relatedValueToStore , relatedObjectBeforeCallbacks , potentiallyRecreatedNewRelatedObject );
612
+ relationshipHandler .handle (relatedValueToStore , relatedObjectBeforeCallbacksApplied , potentiallyRecreatedNewRelatedObject );
598
613
}
599
614
600
615
relationshipHandler .applyFinalResultToOwner (propertyAccessor );
@@ -615,8 +630,9 @@ private <Y> Long queryRelatedNode(Object entity, Neo4jPersistentEntity<?> target
615
630
targetNodeDescription .getIdExpression ().isEqualTo (parameter (Constants .NAME_OF_ID )))
616
631
.returning (Constants .NAME_OF_INTERNAL_ID )
617
632
.build ())
618
- )
619
- .in (inDatabase ).bindAll (Collections .singletonMap (Constants .NAME_OF_ID , idValue ))
633
+ )
634
+ .in (inDatabase ).bindAll (Collections .singletonMap (Constants .NAME_OF_ID ,
635
+ neo4jMappingContext .getConversionService ().convert (idValue , Value .class )))
620
636
.fetchAs (Long .class ).one ().get ();
621
637
}
622
638
0 commit comments