Mapping Exception with a relationship between two nodes of the same type in Neo4j and Spring Data

1.2k views Asked by At

I have a problem when I try to retrieve two nodes with the same label (the same type) and a relathioship between both whit spring data.

enter image description here

I did a query for get the last one, like that:

 @Query("MATCH (b1:Block)-[rel]->(b2) " +
        "WHERE NOT (b1)<-[]-() " +
        "RETURN *; ")
Block findLast();

And the Block attributes are:

 @GraphId
    private Long id;

    private String hash;

    @Relationship(direction = Relationship.OUTGOING)
    private Block predecessor;

The problem is that the ogm says that there is two results (I supose b1 and b2), and throw this exception:

Caused by: java.lang.RuntimeException: Result not of expected size. Expected 1 row but found 2
    at org.neo4j.ogm.session.delegates.ExecuteQueriesDelegate.queryForObject(ExecuteQueriesDelegate.java:73) ~[neo4j-ogm-core-2.1.5.jar:na]
    at org.neo4j.ogm.session.Neo4jSession.queryForObject(Neo4jSession.java:382) ~[neo4j-ogm-core-2.1.5.jar:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_121]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_121]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_121]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_121]

I understand that the OGM can not choise what node is returned in the @Query method, because find two nodes of the same type, but how can I fill the second one into the first one??

Thanks!!!!

1

There are 1 answers

0
meistermeier On

Your interpretation of OGMs behaviour in this case with a custom query is right. There is no chance for OGM to distinguish between the two Block entities.

I do think the only option you have here is to introduce a @QueryResult class and return an instance of it instead of a Block object.

@QueryResult
public class BlockResult {
     private Block predecessor;
    /* other fields and/or relationships */
}

This class needs to live in the package(s) for entity scans. Then you could change your annotated query method to something like:

@Query("MATCH (b1:Block)-[rel]->(b2) " +
    "WHERE NOT (b1)<-[]-() " +
    "RETURN b1, rel, b2 as predecessor; ")
Block findLast();

The important bit here is the as predecessor part because SDN needs to know the 'column' name in the result to match it in the QueryResult object.