Skip to content

Commit 0b856be

Browse files
committed
GH-2305 - Add association support for DTO projections.
1 parent f841eb2 commit 0b856be

File tree

3 files changed

+32
-12
lines changed

3 files changed

+32
-12
lines changed

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

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import org.springframework.data.mapping.PersistentPropertyAccessor;
3434
import org.springframework.data.mapping.PreferredConstructor;
3535
import org.springframework.data.mapping.PreferredConstructor.Parameter;
36+
import org.springframework.data.mapping.SimpleAssociationHandler;
3637
import org.springframework.data.mapping.SimplePropertyHandler;
3738
import org.springframework.data.mapping.model.ParameterValueProvider;
3839
import org.springframework.data.util.ClassTypeInformation;
@@ -105,19 +106,29 @@ public Object getParameterValue(Parameter parameter) {
105106
});
106107

107108
PersistentPropertyAccessor<Object> dtoAccessor = targetEntity.getPropertyAccessor(dto);
108-
targetEntity.doWithProperties((SimplePropertyHandler) property -> {
109+
targetEntity.doWithProperties((SimplePropertyHandler) property ->
110+
setPropertyOnDtoObject(entityInstanceAndSource, sourceEntity, sourceAccessor, constructor, dtoAccessor, property));
109111

110-
if (constructor.isConstructorParameter(property)) {
111-
return;
112-
}
113-
114-
Object propertyValue = getPropertyValueFor(property, sourceEntity, sourceAccessor, entityInstanceAndSource);
115-
dtoAccessor.setProperty(property, propertyValue);
112+
targetEntity.doWithAssociations((SimpleAssociationHandler) association -> {
113+
PersistentProperty<?> property = association.getInverse();
114+
setPropertyOnDtoObject(entityInstanceAndSource, sourceEntity, sourceAccessor, constructor, dtoAccessor, property);
116115
});
117116

118117
return dto;
119118
}
120119

120+
private void setPropertyOnDtoObject(EntityInstanceWithSource entityInstanceAndSource, PersistentEntity<?, ?> sourceEntity,
121+
PersistentPropertyAccessor<Object> sourceAccessor, PreferredConstructor<?, ?> constructor,
122+
PersistentPropertyAccessor<Object> dtoAccessor, PersistentProperty<?> property) {
123+
124+
if (constructor.isConstructorParameter(property)) {
125+
return;
126+
}
127+
128+
Object propertyValue = getPropertyValueFor(property, sourceEntity, sourceAccessor, entityInstanceAndSource);
129+
dtoAccessor.setProperty(property, propertyValue);
130+
}
131+
121132
@Nullable
122133
Object getPropertyValueFor(PersistentProperty<?> targetProperty, PersistentEntity<?, ?> sourceEntity,
123134
PersistentPropertyAccessor sourceAccessor, EntityInstanceWithSource entityInstanceAndSource) {

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1301,9 +1301,9 @@ private void createOneToOneScenarioForNullValues() {
13011301
);
13021302
}
13031303

1304-
private void assertOneToOneScenarioWithNulls(List<OneToOneSource> oneToOnes) {
1304+
private void assertOneToOneScenarioWithNulls(List<OneToOneSource.OneToOneSourceProjection> oneToOnes) {
13051305
assertThat(oneToOnes).hasSize(2);
1306-
assertThat(oneToOnes).extracting(OneToOneSource::getName).containsExactlyInAnyOrder("s1", "s2");
1306+
assertThat(oneToOnes).extracting(OneToOneSource.OneToOneSourceProjection::getName).containsExactlyInAnyOrder("s1", "s2");
13071307
assertThat(oneToOnes).filteredOn(s -> s.getTarget() != null)
13081308
.extracting(s -> s.getTarget().getName()).containsExactly("t1");
13091309
}
@@ -1312,7 +1312,7 @@ private void assertOneToOneScenarioWithNulls(List<OneToOneSource> oneToOnes) {
13121312
void shouldFindOneToOneWithNullValues(@Autowired OneToOneRepository repository) {
13131313
createOneToOneScenarioForNullValues();
13141314

1315-
List<OneToOneSource> oneToOnes = repository.findAllWithNullValues();
1315+
List<OneToOneSource.OneToOneSourceProjection> oneToOnes = repository.findAllWithNullValues();
13161316
assertOneToOneScenarioWithNulls(oneToOnes);
13171317
}
13181318
}
@@ -4146,8 +4146,8 @@ interface OneToOneRepository extends Neo4jRepository<OneToOneSource, String> {
41464146
@Query("MATCH (p1:#{#staticLabels})-[r:OWNS]-(p2) return *")
41474147
List<OneToOneSource> findAllWithCustomQueryReturnStar();
41484148

4149-
@Query("MATCH (p1:#{#staticLabels}) OPTIONAL MATCH (p1)-[r:OWNS]->(p2) return p1, r, p2")
4150-
List<OneToOneSource> findAllWithNullValues();
4149+
@Query("MATCH (p1:#{#staticLabels}) OPTIONAL MATCH (p1)-[r:OWNS]->(p2:OneToOneTarget) return p1, r, p2")
4150+
List<OneToOneSource.OneToOneSourceProjection> findAllWithNullValues();
41514151
}
41524152

41534153
interface RelationshipRepository extends Neo4jRepository<PersonWithRelationship, Long> {

src/test/java/org/springframework/data/neo4j/integration/shared/common/OneToOneSource.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,13 @@ public class OneToOneSource {
3535

3636
@Relationship("OWNS")
3737
private OneToOneTarget target;
38+
39+
/**
40+
* Simple DTO projection for OneToOneSource
41+
*/
42+
@Data
43+
public static class OneToOneSourceProjection {
44+
String name;
45+
OneToOneTarget target;
46+
}
3847
}

0 commit comments

Comments
 (0)