Skip to content

Commit 8b39ed4

Browse files
committed
DATAGRAPH-1414 - Improve relationship documentation.
1 parent d094857 commit 8b39ed4

File tree

6 files changed

+36
-17
lines changed

6 files changed

+36
-17
lines changed

src/main/asciidoc/appendix/query-creation.adoc

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ A save operation call in general issues multiple statements against the database
3838
. For the next defined relationship on the root entity start with 2. but replace _first_ with _next_.
3939

4040

41-
NOTE: As you can see SDN does its best to keep your graph model in sync with the Java world.
41+
WARNING: As you can see SDN does its best to keep your graph model in sync with the Java world.
4242
This is one of the reasons why we really advise you to not load, manipulate and save sub-graphs as this might cause relationships to get removed from the database.
4343

4444
=== Multiple entities
@@ -84,3 +84,10 @@ The above return part will then look like:
8484

8585
The map projection and pattern comprehension used by SDN ensures that only the properties and relationships you have defined are getting queried.
8686

87+
In cases where you have self-referencing nodes or creating schemas that potentially lead to cycles in the data that gets returned,
88+
SDN falls back to a path-based query creation that does a wildcard mapping on all available relationship types reachable from
89+
the initial domain entity.
90+
91+
The return pattern looks similar to this:
92+
93+
`RETURN n{..., __paths__: [p = (n)-[:HAS|KNOWS*]-() | p]}`

src/main/asciidoc/object-mapping/mapping.adoc

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -133,15 +133,15 @@ The `type` or the `value` attribute allow configuration of the relationship's ty
133133
The default direction in SDN is `Relationship.Direction#OUTGOING`.
134134

135135
We support dynamic relationships.
136-
Dynamic relationships are represented as a `Map<String, AnnotatedDomainClass>`.
136+
Dynamic relationships are represented as a `Map<String, AnnotatedDomainClass>` or `Map<Enum, AnnotatedDomainClass>`.
137137
In such a case, the type of the relationship to the other domain class is given by the maps key and must not be configured through the `@Relationship`.
138138

139139
==== Map relationship properties
140140

141141
Neo4j supports defining properties not only on nodes but also on relationships.
142142
To express those properties in the model SDN provides `@RelationshipProperties` to be applied on a simple Java class.
143-
144-
In the entity class the relationship can be modelled as before but its type has to be a `Map` with the related node as the key and the relation property class as value.
143+
Within the properties class there have to be exactly one field marked as `@TargetNode` to define the entity the relationship points towards.
144+
Or, in an `INCOMING` relationship context, is coming from.
145145

146146
A relationship property class and its usage may look like this:
147147

@@ -157,15 +157,18 @@ include::../../../../src/test/java/org/springframework/data/neo4j/documentation/
157157
include::../../../../src/test/java/org/springframework/data/neo4j/documentation/domain/MovieEntity.java[tags=mapping.relationship.properties]
158158
----
159159

160-
==== Relationship query limit
160+
==== Relationship query remarks
161161

162162
In general there is no limitation of relationships / hops for creating the queries.
163163
SDN parses the whole reachable graph from your modelled nodes.
164-
It is possible to have self-referencing entities and self-referencing concrete instances.
165164

166-
If these entities or instances for a cycle we have a strict limit of *2* repetitions of walking the same path through the graph.
167-
E.g. You model a social network of `(:Person)-[:HAS_FRIEND]->(:Person)-[:HAS_FRIEND]...` you will only get the friends of the second degree.
168-
If you need a more specific mapping for your domain we advise you to use custom queries.
165+
This said, when there is the idea of mapping a relationship bidirectional, meaning you define the relationship on both ends of your entity,
166+
you might do not only get what you are expecting.
167+
168+
Consider an example where a _movie_ has _actors_, and you want to fetch a certain movie with all its actors.
169+
This won't be problematical if the relationship from _movie_ to _actor_ were just unidirectional.
170+
In a bidirectional scenario SDN would fetch the particular _movie_, its _actors_ but also the other movies defined for this _actor_ per definition of the relationship.
171+
In the worst case, this will cascade to fetching the whole graph for a single entity.
169172

170173
=== A complete example
171174

src/test/java/org/springframework/data/neo4j/documentation/domain/MovieEntity.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ public class MovieEntity {
4343
@Property("tagline") // <.>
4444
private final String description;
4545

46-
@Relationship(type = "ACTED_IN", direction = Direction.INCOMING) // <.>
4746
// tag::mapping.relationship.properties[]
48-
private Map<PersonEntity, Roles> actorsAndRoles = new HashMap<>();
47+
@Relationship(type = "ACTED_IN", direction = Direction.INCOMING) // <.>
48+
private List<Roles> actorsAndRoles;
4949
// end::mapping.relationship.properties[]
5050

5151
@Relationship(type = "DIRECTED", direction = Direction.INCOMING) private List<PersonEntity> directors = new ArrayList<>();
@@ -66,7 +66,7 @@ public String getDescription() {
6666
return description;
6767
}
6868

69-
public Map<PersonEntity, Roles> getActorsAndRoles() {
69+
public List<Roles> getActorsAndRoles() {
7070
return actorsAndRoles;
7171
}
7272

src/test/java/org/springframework/data/neo4j/documentation/domain/Roles.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import java.util.List;
1919

2020
import org.springframework.data.neo4j.core.schema.RelationshipProperties;
21+
import org.springframework.data.neo4j.core.schema.TargetNode;
2122

2223
/**
2324
* @author Gerrit Meier
@@ -28,7 +29,11 @@ public class Roles {
2829

2930
private final List<String> roles;
3031

31-
public Roles(List<String> roles) {
32+
@TargetNode
33+
private final PersonEntity person;
34+
35+
public Roles(PersonEntity person, List<String> roles) {
36+
this.person = person;
3237
this.roles = roles;
3338
}
3439

src/test/java/org/springframework/data/neo4j/documentation/spring_boot/ReactiveTemplateExampleTest.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,10 @@ void shouldSaveAndReadEntities(@Autowired ReactiveNeo4jTemplate neo4jTemplate) {
5959
"A movie that follows the adventures of Herbie, Herbie's driver, "
6060
+ "Jim Douglas (Dean Jones), and Jim's love interest, " + "Carole Bennett (Michele Lee)");
6161

62-
movie.getActorsAndRoles().put(new PersonEntity(1931, "Dean Jones"), new Roles(Collections.singletonList("Didi")));
63-
movie.getActorsAndRoles().put(new PersonEntity(1942, "Michele Lee"), new Roles(Collections.singletonList("Michi")));
62+
Roles role1 = new Roles(new PersonEntity(1931, "Dean Jones"), Collections.singletonList("Didi"));
63+
Roles role2 = new Roles(new PersonEntity(1942, "Michele Lee"), Collections.singletonList("Michi"));
64+
movie.getActorsAndRoles().add(role1);
65+
movie.getActorsAndRoles().add(role2);
6466

6567
StepVerifier.create(neo4jTemplate.save(movie)).expectNextCount(1L).verifyComplete();
6668

src/test/java/org/springframework/data/neo4j/documentation/spring_boot/TemplateExampleTest.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,10 @@ void shouldSaveAndReadEntities(@Autowired Neo4jTemplate neo4jTemplate) {
4646
"A movie that follows the adventures of Herbie, Herbie's driver, "
4747
+ "Jim Douglas (Dean Jones), and Jim's love interest, " + "Carole Bennett (Michele Lee)");
4848

49-
movie.getActorsAndRoles().put(new PersonEntity(1931, "Dean Jones"), new Roles(Collections.singletonList("Didi")));
50-
movie.getActorsAndRoles().put(new PersonEntity(1942, "Michele Lee"), new Roles(Collections.singletonList("Michi")));
49+
Roles roles1 = new Roles(new PersonEntity(1931, "Dean Jones"), Collections.singletonList("Didi"));
50+
Roles roles2 = new Roles(new PersonEntity(1942, "Michele Lee"), Collections.singletonList("Michi"));
51+
movie.getActorsAndRoles().add(roles1);
52+
movie.getActorsAndRoles().add(roles2);
5153

5254
neo4jTemplate.save(movie);
5355

0 commit comments

Comments
 (0)