Skip to content

Commit 49c399e

Browse files
committed
GH-2141 - Return immutable entity with set id.
1 parent 2b4dc65 commit 49c399e

File tree

6 files changed

+148
-16
lines changed

6 files changed

+148
-16
lines changed

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

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -249,15 +249,11 @@ private <T> T saveImpl(T instance, @Nullable String inDatabase) {
249249
}
250250

251251
PersistentPropertyAccessor<T> propertyAccessor = entityMetaData.getPropertyAccessor(entityToBeSaved);
252-
if (!entityMetaData.isUsingInternalIds()) {
253-
processRelations(entityMetaData, entityToBeSaved, isEntityNew, inDatabase);
254-
return entityToBeSaved;
255-
} else {
252+
if (entityMetaData.isUsingInternalIds()) {
256253
propertyAccessor.setProperty(entityMetaData.getRequiredIdProperty(), optionalInternalId.get());
257-
processRelations(entityMetaData, entityToBeSaved, isEntityNew, inDatabase);
258-
259-
return propertyAccessor.getBean();
254+
entityToBeSaved = propertyAccessor.getBean();
260255
}
256+
return processRelations(entityMetaData, entityToBeSaved, isEntityNew, inDatabase);
261257
}
262258

263259
private <T> DynamicLabels determineDynamicLabels(T entityToBeSaved, Neo4jPersistentEntity<?> entityMetaData,
@@ -437,14 +433,14 @@ private <T> ExecutableQuery<T> createExecutableQuery(Class<T> domainType, String
437433
return toExecutableQuery(preparedQuery);
438434
}
439435

440-
private void processRelations(Neo4jPersistentEntity<?> neo4jPersistentEntity, Object parentObject,
436+
private <T> T processRelations(Neo4jPersistentEntity<?> neo4jPersistentEntity, Object parentObject,
441437
boolean isParentObjectNew, @Nullable String inDatabase) {
442438

443-
processNestedRelations(neo4jPersistentEntity, parentObject, isParentObjectNew, inDatabase,
439+
return processNestedRelations(neo4jPersistentEntity, parentObject, isParentObjectNew, inDatabase,
444440
new NestedRelationshipProcessingStateMachine());
445441
}
446442

447-
private void processNestedRelations(Neo4jPersistentEntity<?> sourceEntity, Object parentObject,
443+
private <T> T processNestedRelations(Neo4jPersistentEntity<?> sourceEntity, Object parentObject,
448444
boolean isParentObjectNew, @Nullable String inDatabase, NestedRelationshipProcessingStateMachine stateMachine) {
449445

450446
PersistentPropertyAccessor<?> propertyAccessor = sourceEntity.getPropertyAccessor(parentObject);
@@ -541,16 +537,20 @@ private void processNestedRelations(Neo4jPersistentEntity<?> sourceEntity, Objec
541537
.setProperty(idProperty, relationshipInternalId.get());
542538
}
543539

540+
PersistentPropertyAccessor<?> targetPropertyAccessor = targetEntity.getPropertyAccessor(relatedNode);
544541
// if an internal id is used this must get set to link this entity in the next iteration
545542
if (targetEntity.isUsingInternalIds()) {
546-
PersistentPropertyAccessor<?> targetPropertyAccessor = targetEntity.getPropertyAccessor(relatedNode);
547543
targetPropertyAccessor.setProperty(targetEntity.getRequiredIdProperty(), relatedInternalId);
548544
}
549545
if (processState != ProcessState.PROCESSED_ALL_VALUES) {
550-
processNestedRelations(targetEntity, relatedNode, isEntityNew, inDatabase, stateMachine);
546+
processNestedRelations(targetEntity, targetPropertyAccessor.getBean(), isEntityNew, inDatabase, stateMachine);
551547
}
552548
}
549+
550+
553551
});
552+
553+
return (T) propertyAccessor.getBean();
554554
}
555555

556556
private <Y> Long saveRelatedNode(Object entity, Class<Y> entityType, NodeDescription targetNodeDescription,

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -668,9 +668,9 @@ private Mono<Void> processNestedRelations(Neo4jPersistentEntity<?> sourceEntity,
668668
targetEntity, inDatabase).flatMap(relatedInternalId -> {
669669

670670
// if an internal id is used this must get set to link this entity in the next iteration
671+
PersistentPropertyAccessor<?> targetPropertyAccessor = targetEntity
672+
.getPropertyAccessor(relatedNode);
671673
if (targetEntity.isUsingInternalIds()) {
672-
PersistentPropertyAccessor<?> targetPropertyAccessor = targetEntity
673-
.getPropertyAccessor(relatedNode);
674674
targetPropertyAccessor.setProperty(targetEntity.getRequiredIdProperty(),
675675
relatedInternalId);
676676
}
@@ -697,7 +697,7 @@ private Mono<Void> processNestedRelations(Neo4jPersistentEntity<?> sourceEntity,
697697

698698
if (processState != ProcessState.PROCESSED_ALL_VALUES) {
699699
return relationshipCreationMonoNested.checkpoint().then(
700-
processNestedRelations(targetEntity, relatedNode,
700+
processNestedRelations(targetEntity, targetPropertyAccessor.getBean(),
701701
isNew, inDatabase, stateMachine));
702702
} else {
703703
return relationshipCreationMonoNested.checkpoint().then();

src/main/java/org/springframework/data/neo4j/core/mapping/NestedRelationshipContext.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,10 +119,10 @@ public static NestedRelationshipContext of(Association<Neo4jPersistentProperty>
119119

120120
Neo4jPersistentProperty inverse = handler.getInverse();
121121

122-
boolean inverseValueIsEmpty = propertyAccessor.getProperty(inverse) == null;
123122
// value can be a collection or scalar of related notes, point to a relationship property (scalar or collection)
124123
// or is a dynamic relationship (map)
125124
Object value = propertyAccessor.getProperty(inverse);
125+
boolean inverseValueIsEmpty = value == null;
126126

127127
RelationshipDescription relationship = neo4jPersistentEntity.getRelationships().stream()
128128
.filter(r -> r.getFieldName().equals(inverse.getName())).findFirst().get();

src/test/java/org/springframework/data/neo4j/integration/imperative/RepositoryIT.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@
103103
import org.springframework.data.neo4j.integration.shared.common.FriendshipRelationship;
104104
import org.springframework.data.neo4j.integration.shared.common.Hobby;
105105
import org.springframework.data.neo4j.integration.shared.common.ImmutablePerson;
106+
import org.springframework.data.neo4j.integration.shared.common.ImmutablePersonWithGeneratedId;
106107
import org.springframework.data.neo4j.integration.shared.common.Inheritance;
107108
import org.springframework.data.neo4j.integration.shared.common.KotlinPerson;
108109
import org.springframework.data.neo4j.integration.shared.common.LikesHobbyRelationship;
@@ -1760,6 +1761,21 @@ void saveAllWithConvertedId(@Autowired EntityWithConvertedIdRepository repositor
17601761
assertThat(node.get("e").get("identifyingEnum").asString()).isEqualTo("A");
17611762
}
17621763
}
1764+
1765+
@Test // GH-2141
1766+
void saveWithGeneratedIdsReturnsObjectWithIdSet(
1767+
@Autowired ImmutablePersonWithGeneratedIdRepository repository) {
1768+
1769+
ImmutablePersonWithGeneratedId fallback1 = new ImmutablePersonWithGeneratedId();
1770+
ImmutablePersonWithGeneratedId fallback2 = new ImmutablePersonWithGeneratedId(fallback1);
1771+
ImmutablePersonWithGeneratedId person = new ImmutablePersonWithGeneratedId(fallback2);
1772+
1773+
ImmutablePersonWithGeneratedId savedPerson = repository.save(person);
1774+
1775+
assertThat(savedPerson.getId()).isNotNull();
1776+
assertThat(savedPerson.getFallback()).isNotNull();
1777+
assertThat(savedPerson.getFallback().getFallback()).isNotNull();
1778+
}
17631779
}
17641780

17651781
@Nested
@@ -3800,6 +3816,8 @@ interface LoopingRelationshipRepository extends Neo4jRepository<DeepRelationship
38003816

38013817
interface ImmutablePersonRepository extends Neo4jRepository<ImmutablePerson, String> {}
38023818

3819+
interface ImmutablePersonWithGeneratedIdRepository extends Neo4jRepository<ImmutablePersonWithGeneratedId, Long> {}
3820+
38033821
interface MultipleLabelRepository extends Neo4jRepository<MultipleLabels.MultipleLabelsEntity, Long> {}
38043822

38053823
interface MultipleLabelWithAssignedIdRepository

src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveRepositoryIT.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
import org.springframework.data.neo4j.integration.shared.common.DtoPersonProjection;
2323
import org.springframework.data.neo4j.integration.shared.common.EntitiesWithDynamicLabels;
24+
import org.springframework.data.neo4j.integration.shared.common.ImmutablePersonWithGeneratedId;
2425
import org.springframework.data.neo4j.integration.shared.common.SimplePerson;
2526
import org.springframework.data.neo4j.integration.shared.common.ThingWithFixedGeneratedId;
2627
import reactor.core.publisher.Flux;
@@ -1738,6 +1739,23 @@ void saveAllWithConvertedId(@Autowired EntityWithConvertedIdRepository repositor
17381739
assertThat(node.get("e").get("identifyingEnum").asString()).isEqualTo("A");
17391740
}
17401741
}
1742+
1743+
@Test
1744+
void saveWithGeneratedIdsReturnsObjectWithIdSet(
1745+
@Autowired ImmutablePersonWithGeneratedIdRepository repository) {
1746+
1747+
ImmutablePersonWithGeneratedId fallback1 = new ImmutablePersonWithGeneratedId();
1748+
ImmutablePersonWithGeneratedId fallback2 = new ImmutablePersonWithGeneratedId(fallback1);
1749+
ImmutablePersonWithGeneratedId person = new ImmutablePersonWithGeneratedId(fallback2);
1750+
1751+
StepVerifier.create(repository.save(person))
1752+
.assertNext(savedPerson -> {
1753+
assertThat(savedPerson.getId()).isNotNull();
1754+
assertThat(savedPerson.getFallback()).isNotNull();
1755+
assertThat(savedPerson.getFallback().getFallback()).isNotNull();
1756+
})
1757+
.verifyComplete();
1758+
}
17411759
}
17421760

17431761
@Nested
@@ -2420,6 +2438,9 @@ interface BidirectionalEndRepository extends ReactiveNeo4jRepository<Bidirection
24202438

24212439
interface ImmutablePersonRepository extends ReactiveNeo4jRepository<ImmutablePerson, String> {}
24222440

2441+
interface ImmutablePersonWithGeneratedIdRepository
2442+
extends ReactiveNeo4jRepository<ImmutablePersonWithGeneratedId, Long> {}
2443+
24232444
interface ReactiveLoopingRelationshipRepository
24242445
extends ReactiveNeo4jRepository<DeepRelationships.LoopingType1, Long> {}
24252446

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
* Copyright 2011-2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.neo4j.integration.shared.common;
17+
18+
import org.springframework.data.annotation.PersistenceConstructor;
19+
import org.springframework.data.neo4j.core.schema.GeneratedValue;
20+
import org.springframework.data.neo4j.core.schema.Id;
21+
import org.springframework.data.neo4j.core.schema.Node;
22+
23+
import java.util.Collections;
24+
import java.util.List;
25+
import java.util.Map;
26+
import java.util.Set;
27+
28+
/**
29+
* @author Gerrit Meier
30+
*/
31+
@Node
32+
public class ImmutablePersonWithGeneratedId {
33+
@Id @GeneratedValue
34+
private final Long id;
35+
private final List<ImmutablePersonWithGeneratedId> wasOnboardedBy;
36+
private final Set<ImmutablePersonWithGeneratedId> knownBy;
37+
private final Map<String, ImmutablePersonWithGeneratedId> ratedBy;
38+
private final ImmutablePersonWithGeneratedId fallback;
39+
40+
@PersistenceConstructor
41+
public ImmutablePersonWithGeneratedId(Long id,
42+
List<ImmutablePersonWithGeneratedId> wasOnboardedBy,
43+
Set<ImmutablePersonWithGeneratedId> knownBy,
44+
Map<String, ImmutablePersonWithGeneratedId> ratedBy,
45+
ImmutablePersonWithGeneratedId fallback) {
46+
47+
this.id = id;
48+
this.wasOnboardedBy = wasOnboardedBy;
49+
this.knownBy = knownBy;
50+
this.ratedBy = ratedBy;
51+
this.fallback = fallback;
52+
}
53+
54+
public ImmutablePersonWithGeneratedId() {
55+
this(null, Collections.emptyList(), Collections.emptySet(), Collections.emptyMap(), null);
56+
}
57+
58+
public ImmutablePersonWithGeneratedId(List<ImmutablePersonWithGeneratedId> wasOnboardedBy) {
59+
this(null, wasOnboardedBy, Collections.emptySet(), Collections.emptyMap(), null);
60+
}
61+
62+
public ImmutablePersonWithGeneratedId(Set<ImmutablePersonWithGeneratedId> knownBy) {
63+
this(null, null, knownBy, Collections.emptyMap(), null);
64+
}
65+
66+
public ImmutablePersonWithGeneratedId(Map<String, ImmutablePersonWithGeneratedId> ratedBy) {
67+
this(null, null, Collections.emptySet(), ratedBy, null);
68+
}
69+
70+
public ImmutablePersonWithGeneratedId(ImmutablePersonWithGeneratedId fallback) {
71+
this(null, null, Collections.emptySet(), Collections.emptyMap(), fallback);
72+
}
73+
74+
public Long getId() {
75+
return id;
76+
}
77+
78+
public List<ImmutablePersonWithGeneratedId> getWasOnboardedBy() {
79+
return wasOnboardedBy;
80+
}
81+
82+
public Set<ImmutablePersonWithGeneratedId> getKnownBy() {
83+
return knownBy;
84+
}
85+
86+
public Map<String, ImmutablePersonWithGeneratedId> getRatedBy() {
87+
return ratedBy;
88+
}
89+
90+
public ImmutablePersonWithGeneratedId getFallback() {
91+
return fallback;
92+
}
93+
}

0 commit comments

Comments
 (0)