背景
依赖
springboot版本 2.7.10
本地neo4j安装的版本:4.4.19
依赖如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-neo4j</artifactId>
</dependency>
springboot整合neo4j官网地址:Accessing Data with Neo4j
遇到的问题:
按照官网向导本地运行后,得不到正确的关系
neo4j得到的数据如下:
greg = personRepository.findByName(greg.getName());
greg.worksWith(roy);
greg.worksWith(craig);
personRepository.save(greg);
roy = personRepository.findByName(roy.getName());
roy.worksWith(craig);
// We already know that roy works with greg
personRepository.save(roy);
log.info("Lookup each person by name...");
team.stream().forEach(person -> log.info(
"\t" + personRepository.findByName(person.getName()).toString()));
上面代码设置了greg的同事是roy,但是查询roy的同事确无法得到greg。
问题原因分析过程
参考资料1:
首先从官方github找相关issue,有人遇到同类问题,并得到回复如下(问题连接地址:https://stackoverflow.com/questions/68472313/spring-data-neo4j-6-relationship-undirected)。
也就是说在早期版本,我们可以在关系这里设置UNDIRECTED属性,实现数据间的双向关系。但是后来出于特别的考虑,Neo4j中的关系都是带有方向的关系,不再支持UNDIRECTORY这个属性(Neo4j-OGM支持?)
参考资料2:
官方示例代码在Person实体中也写了注释,大意和上述一致,而且给了连接(https://dzone.com/articles/modelling-data-neo4j)
/**
* Neo4j doesn't REALLY have bi-directional relationships. It just means when querying
* to ignore the direction of the relationship.
* https://dzone.com/articles/modelling-data-neo4j
*/
@Relationship(type = "TEAMMATES",direction = Relationship.Direction.INCOMING)
public Set<Person> teammates;
在这个连接中主要介绍了directed relationships 和 bidirectional relationships之间的区别及具体使用场景。
得到的核心信息如下:
这里引入了Cypher语法,也就是通过这些语法能够在neo4J中进行增删改查。通过模仿+实践得到结果如下:
MATCH (p1:Person)-[r:TEAMMATES]-(p2:Person) where p1.name = 'Roy' RETURN p2
此图结果表明,通过 - 查询是忽略关系方向的,能够得到roy的同事有Greg
MATCH (p1:Person)<-[r:TEAMMATES]-(p2:Person) where p1.name = 'Roy' RETURN p2
此图结果表明,通过 -> 查询是带有关系方向的,得不到roy的同事有Greg
解决办法
自定义查询语句,使用-查询忽略方向即可,修改如下
@Query("MATCH (p1:Person)-[r:TEAMMATES]-(p2:Person) where p1.name = $name RETURN p2")
List<Person> findByTeammatesName(String name);
按照官网demo的打印依然无法得到预期结果,因为数据库中虽然支持查询双向关系,但是并不能自动关联到java的Person对象的teammates中,所以我这里手动查询关系,再把关系设置到java实体中并打印即可。
在AccessingDataNeo4jApplication中修改如下
log.info("-------------Lookup each person by name from neo4j...");
team.forEach(p -> {
List<Person> teammatesName = personRepository.findByTeammatesName(p.getName());
p.setTeammates(new HashSet<>(teammatesName));
log.info("\t" + p.toString());
});
验证
再次运行程序,得到正确结果: