具有自定义查询和复合实体的Neo4j SDN4存储库方法

时间:2017-09-20 14:25:12

标签: neo4j cypher spring-data-neo4j-4 neo4j-ogm

我有以下SDN 4实体:

@NodeEntity
public class Decision {


    @Relationship(type = CONTAINS, direction = Relationship.INCOMING)
    private Set<Decision> parentDecisions;

...
}

我想通过id找到这个实体,并使用以下SDN4存储库方法和自定义Cypher查询返回其所有parentDecisions

MATCH (d:Decision) WHERE d.id = {decisionId} OPTIONAL MATCH (d)<-[rdp:CONTAINS]-(parentD:Decision) RETURN d, rdp, parentD
Decision getById(@Param("decisionId") Long decisionId);

现在,在现有parentD的情况下,它失败并出现以下异常:

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)

如何使用SDN4存储库方法和自定义Cypher查询正确实现此逻辑?

已更新

我测试了 frant.hartm 建议的方法。不幸的是它仍然不起作用。

例如,以下SDN4存储库方法正确返回2 Decision

@Query("MATCH (d:Decision)-[drd:FOLLOWS]->(following:Decision) WHERE d.id = {decisionId} RETURN following")
List<Decision> test(@Param("decisionId") Long decisionId);

但下一个:

@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);

仅返回主decisionholder.getDecision()),但会收到followDholder.getDecision().getFollowDecisions())决定的空集合。

这是Decision实体:

@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;
    }

....

}

我做错了什么?

1 个答案:

答案 0 :(得分:3)

核心问题是您的查询会返回多个Decision个实例(在不同的变量 - dparentD下),因此它无法随意选择一个。使用@QueryResult提取所需的值。也可以使用COLLECT来获得单个结果。

@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);

<强>更新

对于正确映射关系的关系,不得混合使用相同类型的简单关系。

如果你有一个简单的关系和关系实体具有相同的类型

  • 当它们代表相同的关系类型时,在关系定义中使用关系实体类(例如Set<ParentDecisionRelationship> parentDecisions

  • 当他们代表不同类型时,重命名其中一个