我如何使用 GraphRepositories 来 return 具有指定深度的复杂 POJO(目前使用 Neo4j 模板)

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

上下文:

我正在开发一个由 Neo4j 数据库支持的 java spring Web 应用程序。我有一个对象 "Student",它占用了多个 "Modules" 和 "Courses"。该关系通过指定等级 属性 的 "rich relationship" 节点 "RR_TakenModule" 和 "RR_TakenCourse" 连接。

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

这样我就可以要求学生在一个模块中获得 74%

问题:

我无法从 GraphRepository 设置中 return "deep" 对象。即我不能 return 具有填充 "modulesTaken" 和 "coursesTaken" 属性的学生。我在网上看到了几种方法,例如尝试密码查询:

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

声称通过 属性 名称将 RR_TakenModules 动态映射到对象中。它不会为我执行此操作,并且 return 是一个 "Error mapping GraphModel to instance of com.domain.Actors.Student" 错误代码。尽管请注意,当 运行 在 localhost:7474 界面中进行密码查询时,它确实可以正确分组。显然映射是问题所在。

目前我采用的是模板+地图的方式。使用 Neo4jOperations 和结果对象。这行得通,但是意味着我必须写出遍历的迭代器并根据结果对象中的 key/value 对分配值。这导致高维护成本和更大的错误机会。

查看它们曾经是 @Fetch 等选项,并在 Neo4jTemplate 查询中指定深度,但是我的版本中似乎没有这些方法(大多数似乎已贬值)

问题:

有没有办法通过 Graph Repositories 映射 Neo4j 实体对象的子对象(即 "collection prop" 和 "set prop")。 我知道有预定义的方法,例如 "findOne" 具有深度参数,但我想将类似的实现应用于我的自定义查询。

或者,是否有一种解决方案可以将 Neo4jOperations 结果对象动态映射到 java 对象,而无需定义一些自定义 json 解析器

版本:

<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>

在研究了 GraphRepositor 提供的默认 "findOne(nodeid, depth)" 方法后,我找到了适合我的解决方案。

我将查询格式设置为 MATCH (n:Entity) WITH n MATCH p=(n)-[*0..4]->(m) RETURN p 其中 Entity 是您的基本实体的名称。我无法解释为什么,但这种格式会将结果动态映射到您各自的 POJO。

请注意,您可以指定深度 (*0..4) 来指定填充 POJO 的深度。还值得注意的是,该关系使用 -[]-> 而不是 -[]-,这是 findOne(nodeid, depth) 的默认关系。如果这不起作用,您可能没有获得最新的 Neo4j OGM 版本。

Spring Data Neo4j (SDN) 不会填充 returned 节点中的引用(按关系)节点。但是,它将填充 fullNamegender 属性(这里假设 Gender 是一个 Enum,以便可以轻松映射字符串)。

在您上面的查询中,您 return 一个 Student 节点和一个 RR_TakenModule 的集合,但是 Spring 不知道如何映射它,因为没有 class 包含这两个结果。您需要为这种情况定义一个明确的结果。我建议如下:

@NodeEntity(label = "Student")
public class Student extends DomainObject {
    @Property(name = "studentId")
    private String studentId; //you want to have this
    @Property(name = "fullName")
    private String fullName;
    @Property(name = "gender")
    private Gender gender; //assuming its an Enum
    @Relationship(type = "MODULES_TAKEN") // Relationship.OUTGOING is default
    private Set<RR_TakenModule) modulesTaken;
}

然后定义一个存储库

public interface StudentRepository extends GraphRepository<Student> {

    @Query("MATCH (s:Student {studentId:{studentId}})-[:MODULES_TAKEN]->(m:RR_TakenModule) RETURN s AS student, collect(DISTINCT m) AS modulesTaken")
    public StudentWithModulesTakenResult getByUserIdWithModulesTaken(@Param("studentId") String studentId)
}

和各自的结果

@QueryResult
public class StudentWithModulesTakenResult {
    private Student student;
    private Set<RR_TakenModule> modulesTaken;
    //only getters, no setters
}