I have the following SDN 4 entity:
@NodeEntity
public class Decision {
@Relationship(type = CONTAINS, direction = Relationship.INCOMING)
private Set<Decision> parentDecisions;
...
}
I'd like to find this entity by id and return all its parentDecisions
with a following SDN4 repository method and the custom Cypher query:
MATCH (d:Decision) WHERE d.id = {decisionId} OPTIONAL MATCH (d)<-[rdp:CONTAINS]-(parentD:Decision) RETURN d, rdp, parentD
Decision getById(@Param("decisionId") Long decisionId);
right now in case of existing parentD
it fails with the following exception:
java.lang.RuntimeException: Result not of expected size. Expected 1 row but found 3
at org.neo4j.ogm.session.delegates.ExecuteQueriesDelegate.queryForObject(ExecuteQueriesDelegate.java:73)
at org.neo4j.ogm.session.Neo4jSession.queryForObject(Neo4jSession.java:382)
at sun.reflect.GeneratedMethodAccessor111.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
How to properly implement this logic with SDN4 repository method and the custom Cypher query ?
UPDATED
I tested approach suggested by frant.hartm. Unfortunately it still doesn't work.
For example the following SDN4 repository method correctly returns 2 Decision
:
@Query("MATCH (d:Decision)-[drd:FOLLOWS]->(following:Decision) WHERE d.id = {decisionId} RETURN following")
List<Decision> test(@Param("decisionId") Long decisionId);
but the next one:
@Query("MATCH (d:Decision) WHERE d.id = {decisionId} OPTIONAL MATCH (d)-[rdf:FOLLOWS]->(followD:Decision) RETURN d as decision, collect(rdf), collect(followD) ")
DecisionHolder test1(@Param("decisionId") Long decisionId);
returns only main decision
(holder.getDecision()
) but with empty collection of followD
(holder.getDecision().getFollowDecisions()
) Decision.
This is Decision
entity:
@NodeEntity
public class Decision {
private static final String FOLLOWS = "FOLLOWS";
@Relationship(type = FOLLOWS, direction = Relationship.INCOMING)
private Set<Decision> followDecisions;
@Relationship(type = FOLLOWS, direction = Relationship.INCOMING)
public Set<Decision> getFollowDecisions() {
return followDecisions;
}
@Relationship(type = FOLLOWS, direction = Relationship.INCOMING)
public void setFollowDecisions(Set<Decision> followDecisions) {
this.followDecisions = followDecisions;
}
....
}
What am I doing wrong ?
The core issue is that your query returns multiple Decision
instances (under different variables - d
and parentD
), so it can't just arbitrarily chose one. Use @QueryResult
to extract desired value. Also use COLLECT
to get a single result.
@QueryResult
public class DecisionHolder {
Decision d;
}
MATCH (d:Decision) WHERE d.id = {decisionId} " +
"OPTIONAL MATCH (d)<-[rdp:CONTAINS]-(parentD:Decision) " +
"RETURN d, collect(rdp), collect(parentD)")
DecisionHolder getById(@Param("decisionId") Long decisionId);
Update:
For the relationships to map correctly relationship entities and simple relationships with same type must not be mixed.
If you have a simple relationship and relationship entity with same type
when they represent same relationship type use relationship entity class in your relationship definition (e.g. Set<ParentDecisionRelationship> parentDecisions
)
when they represent different types rename one of them