Jack Dalton Jack Dalton - 2 years ago 104
Java Question

How can I use GraphRepositories to return complex POJO's with a specified depth (currently using Neo4j templating)

CONTEXT:

I am working on a java spring web application backed by a Neo4j database. I have an object "Student" that has taken a number of "Modules" and "Courses". The relationship is connected via "rich relationship" nodes "RR_TakenModule" and "RR_TakenCourse" that specify a grade property.

public class Student extends DomainObject {
String fullName;
Gender gender;
Collection<RR_TakenModule> modulesTaken;
Collection<RR_TakenCourse> coursesTaken;
DateTime yearStarted;


that way I could ask for a Student that got 74% in a Module

PROBLEM:

I cannot return a "deep" object, from the GraphRepository set up. Ie I cannot return a Student with populated "modulesTaken" and "coursesTaken" properties. I've seen several approaches online such as trying the cypher query :

MATCH (student:Student) -[:MODULES_TAKEN]-> (rr:RR_TakenModule) -[:MODULE]-> (m:Module) RETURN student, COLLECT(rr) as modulesTaken


Which is claimed to map the RR_TakenModules into the object dynamically via the property name. It does not do this for me and returns a "Error mapping GraphModel to instance of com.domain.Actors.Student" error code. Although note that it does properly group when running the cypher query in the localhost:7474 interface. Clearly mapping is the issue.

Currently I have adopted the template and Map approach. Using Neo4jOperations and the Result object. This works, however means that I have to write out iterators that go through and assign values based on the key/value pairs in the result object. This leads to high maintenance and a larger chance of errors.

Looking around their used to be options such as @Fetch, and specifying depth in Neo4jTemplate queries, however non of these methods seem to be present in my version (most appear to be depreciated)

QUESTION :

Is there a way to map sub-objects (ie "collection prop" and "set prop") of a Neo4j entity object via Graph Repositories.
I realise there are predefined methods such as "findOne" that have a depth parameter, but I want to apply a similar implementation to my custom queries.

Alternatively, is there a solution for dynamically mapping a Neo4jOperations Result object to a java object without defining some custom json parser

VERSIONS :

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.1.RELEASE</version>
</parent>

<properties>
<java.version>1.8</java.version>
<spring-data-neo4j.version>4.0.0.RELEASE</spring-data-neo4j.version>
<spring-data-releasetrain.version>Gosling-RELEASE</spring-data-releasetrain.version>
</properties>

Answer Source

After looking into the default "findOne(nodeid, depth)" method GraphRepositor offers I have found a solution that works for me.

I format the query as MATCH (n:Entity) WITH n MATCH p=(n)-[*0..4]->(m) RETURN p where Entity is the name of your base entity. I cannot justify why, but this format will dynamically map the result to your respective POJO.

Note you can specify the depth (*0..4) to specify how deep a POJO is populated. It is also worth noting that the relationship is using -[]-> not -[]- which is the default relationship for findOne(nodeid, depth). If this does not work it might be possible that you have not got the latest Neo4j OGM version.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download