Search code examples
javaspring-data-neo4jspring-data-neo4j-4

Spring data Neo4j fetch relationships


I am using spring-data-neo4j V4 and look for solution how to fetch entities which are not directly connected to the loaded entity. To explain:

I do have 3 entities in my neo4j database.

@NodeEntity(label="membership")
public class Membership extends AbstractEntity{

    public Membership(){ }

    private String membershipId;

    @Relationship(type = "IN_YEAR", direction = Relationship.OUTGOING)
    private Set<Year> year = new HashSet<>();

    //getter+setter

}

@NodeEntity(label="year")
public class Year extends AbstractEntity{

    public Year(){}

    private String name;
    private String membershipId;

    @Relationship(type = "IN_MONTH", direction = Relationship.OUTGOING )
    private Set<Month> month = new HashSet<>();

    //getter+setter
}

@NodeEntity(label="month")
public class Month extends AbstractEntity{

    private String name;

    //getter+setter
}

When i call my MembershipRepository and load a Membership by Id:

membershipRepository.findByMembershipId(id);

the year entities will be fetched but the month entities not. Can anybody tell what is the best or recommended way to load the month entities when loading the membership entity? As written in http://docs.spring.io/spring-data/neo4j/docs/current/reference/html/ the @Fetch is obsolete since version 4 so I need another solution.

EDIT: I read in http://docs.spring.io/spring-data/neo4j/docs/current/reference/html/ the workaround for fetch, just use the load methods from the Neo4jTemplate. So I load the months for every year by:

Set<Year> fetchedYear = new HashSet<>();
for(Year year : ms.getYear()){
    fetchedYear.add(neo4jTemplate.load(Year.class, year.getId(), 1));
}   
ms.setYear(fetchedYear);

But is there a better solution?


Solution

  • The first option would be to use loadByProperty and set the loading depth to 2.

    Example:

    neo4jTemplate.loadByProperty(Membership.class, "membershipId", value, 2);
    

    This is available for SDN-4.1.0-Snapshot

    But if you do not want to load a Membership with depth 2 because too much of your graph will be loaded (from other relationships) then I think you could construct a cypher query (using OPTIONAL MATCH), execute it with the neo4jTemplate and retrieve the Object which will then be automatically mapped due to the “smartObjectMapping".

    Example:

    String query = "MATCH (n:Membership{membershipId:{id})-[r]-(m) OPTIONAL MATCH (m:Year)-[e]-(x) RETURN n,r,m,e,x";
    Map<String,Object> map = new HashMap<>();
    map.put("id",value);
    Result result = neo4jTemplate.query(query,map);
    

    now n in the Result should contain all mapped relationships