spring-boot - 使用 Spring Data neo4j - SDN/ReactiveNeo4j 创建重复关系(neo4j 社区版 4.4.4)

标签 spring-boot neo4j spring-data-neo4j

我正在使用 NameEntity 类实现一个基本节点 - [relationship] - 节点,该类具有 Relationship(type="LINK", Direction = INCOMING)注释。

Link 类有一个 @TargetNode NameEntity

我有一个单元测试,它创建三个节点,具有两个关系。我第一次运行单元测试时,会创建节点和关系:

enter image description here

我第二次运行单元测试时,正在创建重复的关系:

enter image description here

我对 neo4j 还很陌生(我使用的是社区版本 4.4.4)。

我不希望创建重复的第二个关系(具有相同的Link类型)。我很高兴我没有使用 Version 属性。

这是 Neo4j 创建第二个关系(具有相同属性)的默认行为吗?有没有办法不创建第二个(重复)关系?

我已附加复制的 NameEntityLink pojo、单元测试以及我运行单元测试时(第一次和第二次)运行的 Cypher。

我“认为”解决方案可能是覆盖 equalshashCode,但非常欢迎提供具体的示例。我还没找到。


NameEntity:

@Node("Name")
@Getter
public class NameEntity {

    @Id
    private String name;

    @Relationship(type = "LINK", direction = INCOMING)
    private List<Link> nameLinks;


    public NameEntity(final String name) {
        this.name = name;
    }

    public NameEntity() {}

    public void install(Link nameLink) {
        if (nameLinks == null) {
            nameLinks = new ArrayList<>();
        }
        nameLinks.add(nameLink);
    }
}

Link(与TargetNode的关系):

@RelationshipProperties
@Getter
public class Link {

    @RelationshipId
    private Long id;

    private String value;

    @TargetNode
    private NameEntity nameEntity;

    public Link(NameEntity nameEntity, String value) {
        this.nameEntity = nameEntity;
        this.value = value;
    }


    // equals and hashCode override does not work

    @Override
    public boolean equals(Object o) {
        if (this == o)
            return true;
        if (!(o instanceof Link))
            return false;
        Link link = (Link) o;
        return Objects.equals(value, link.value)
                && Objects.equals(nameEntity.getName(), link.nameEntity.getName());
    }

    @Override
    public int hashCode() {
        return Objects.hash(value);
    }
    

    public Link() {}

    public NameEntity getNameEntity() {
        return nameEntity;
    }

    public String getValue() {
        return value;
    }
}

Spring Boot首次运行单元测试:

2022-04-13 18:31:33.243 DEBUG 25444 --- [o-auto-1-exec-1] .d.n.c.t.ReactiveNeo4jTransactionManager : Creating new transaction with name [org.springframework.data.neo4j.repository.support.SimpleReactiveNeo4jRepository.save]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
2022-04-13 18:31:33.464  WARN 25444 --- [o4jDriverIO-2-2] o.s.d.n.c.m.DefaultNeo4jIsNewStrategy    : Instances of class com.chocksaway.neo4j.entity.NameEntity with an assigned id will always be treated as new without version property!
2022-04-13 18:31:33.529 DEBUG 25444 --- [o4jDriverIO-2-2] org.springframework.data.neo4j.cypher    : Executing:
MERGE (nameEntity:`Name` {name: $__id__}) SET nameEntity += $__properties__ RETURN nameEntity
2022-04-13 18:31:33.639 DEBUG 25444 --- [o4jDriverIO-2-2] org.springframework.data.neo4j.cypher    : Executing:
MERGE (nameEntity:`Name` {name: $__id__}) SET nameEntity += $__properties__ RETURN nameEntity
2022-04-13 18:31:33.655 DEBUG 25444 --- [o4jDriverIO-2-2] org.springframework.data.neo4j.cypher    : Executing:
MATCH (startNode:`Name`) WHERE startNode.name = $fromId MATCH (endNode) WHERE id(endNode) = $toId CREATE (startNode)<-[relProps:`LINK`]-(endNode) SET relProps += $__properties__ RETURN id(relProps)
2022-04-13 18:31:33.663 DEBUG 25444 --- [o4jDriverIO-2-2] org.springframework.data.neo4j.cypher    : Executing:
MERGE (nameEntity:`Name` {name: $__id__}) SET nameEntity += $__properties__ RETURN nameEntity
2022-04-13 18:31:33.669 DEBUG 25444 --- [o4jDriverIO-2-2] org.springframework.data.neo4j.cypher    : Executing:
MATCH (startNode:`Name`) WHERE startNode.name = $fromId MATCH (endNode) WHERE id(endNode) = $toId CREATE (startNode)<-[relProps:`LINK`]-(endNode) SET relProps += $__properties__ RETURN id(relProps)
2022-04-13 18:31:33.682 DEBUG 25444 --- [o4jDriverIO-2-2] .d.n.c.t.ReactiveNeo4jTransactionManager : Initiating transaction commit
2022-04-13 18:31:33.762  INFO 25444 --- [ionShutdownHook] o.neo4j.driver.internal.InternalDriver   : Closing driver instance 2107393518
2022-04-13 18:31:33.764  INFO 25444 --- [ionShutdownHook] o.n.d.i.async.pool.ConnectionPoolImpl    : Closing connection pool towards localhost:7687

Spring Boot第二次运行单元测试:

2022-04-13 18:33:44.751 DEBUG 16572 --- [o-auto-1-exec-1] .d.n.c.t.ReactiveNeo4jTransactionManager : Creating new transaction with name [org.springframework.data.neo4j.repository.support.SimpleReactiveNeo4jRepository.save]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
2022-04-13 18:33:44.981  WARN 16572 --- [o4jDriverIO-2-2] o.s.d.n.c.m.DefaultNeo4jIsNewStrategy    : Instances of class com.chocksaway.neo4j.entity.NameEntity with an assigned id will always be treated as new without version property!
2022-04-13 18:33:45.044 DEBUG 16572 --- [o4jDriverIO-2-2] org.springframework.data.neo4j.cypher    : Executing:
MERGE (nameEntity:`Name` {name: $__id__}) SET nameEntity += $__properties__ RETURN nameEntity
2022-04-13 18:33:45.143 DEBUG 16572 --- [o4jDriverIO-2-2] org.springframework.data.neo4j.cypher    : Executing:
MERGE (nameEntity:`Name` {name: $__id__}) SET nameEntity += $__properties__ RETURN nameEntity
2022-04-13 18:33:45.160 DEBUG 16572 --- [o4jDriverIO-2-2] org.springframework.data.neo4j.cypher    : Executing:
MATCH (startNode:`Name`) WHERE startNode.name = $fromId MATCH (endNode) WHERE id(endNode) = $toId CREATE (startNode)<-[relProps:`LINK`]-(endNode) SET relProps += $__properties__ RETURN id(relProps)
2022-04-13 18:33:45.168 DEBUG 16572 --- [o4jDriverIO-2-2] org.springframework.data.neo4j.cypher    : Executing:
MERGE (nameEntity:`Name` {name: $__id__}) SET nameEntity += $__properties__ RETURN nameEntity
2022-04-13 18:33:45.185 DEBUG 16572 --- [o4jDriverIO-2-2] org.springframework.data.neo4j.cypher    : Executing:
MATCH (startNode:`Name`) WHERE startNode.name = $fromId MATCH (endNode) WHERE id(endNode) = $toId CREATE (startNode)<-[relProps:`LINK`]-(endNode) SET relProps += $__properties__ RETURN id(relProps)
2022-04-13 18:33:45.211 DEBUG 16572 --- [o4jDriverIO-2-2] .d.n.c.t.ReactiveNeo4jTransactionManager : Initiating transaction commit
2022-04-13 18:33:45.290  INFO 16572 --- [ionShutdownHook] o.neo4j.driver.internal.InternalDriver   : Closing driver instance 1728266914
2022-04-13 18:33:45.293  INFO 16572 --- [ionShutdownHook] o.n.d.i.async.pool.ConnectionPoolImpl    : Closing connection pool towards localhost:7687

单元测试:

@Test
    public void testAddName() throws URISyntaxException {
        RestTemplate restTemplate = new RestTemplate();
        final String baseUrl = "http://localhost:"+randomServerPort+"/name";

        final Link nameEntity1 = new Link(new NameEntity("name001", "Person"), "Link");
        final Link nameEntity2 = new Link(new NameEntity("name002", "Person"), "Link");

        final NameEntity bob = new NameEntity("Bob", "Person");

        bob.setNameLinks(Set.of(nameEntity1, nameEntity2));

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);

        final ResponseEntity<String> response =  restTemplate.postForEntity(baseUrl, bob, String.class);

        Assertions.assertEquals(200, response.getStatusCodeValue());

        Assertions.assertTrue(response.hasBody());
        Assertions.assertTrue(response.getBody().contains("Bob"));
    }

如有任何帮助,我们将不胜感激。

谢谢

英里。

最佳答案

在 Cypher 中,通常使用 MERGE 来避免以这种方式创建重复项。如果您查看 Spring Boot 日志,您将看到节点的创建过程如下:

MERGE (nameEntity:`Name` {name: $__id__}) 
SET nameEntity += $__properties__ 
RETURN nameEntity

使用 MERGE 而不是 CREATE 可确保您的节点不重复。您还可以创建一个约束,在节点上强制执行唯一的“名称”属性,但是当您尝试创建重复项时,这会出错。

现在,如果我们查看创建关系的日志,我们会看到:

MATCH (startNode:`Name`) 
WHERE startNode.name = $fromId 
MATCH (endNode) 
WHERE id(endNode) = $toId 
CREATE (startNode)<-[relProps:`LINK`]-(endNode) 
SET relProps += $__properties__ 
RETURN id(relProps)

此代码查找 (MATCH) 节点,然后创建 (CREATE) 关系。这应该是合并,以避免重复。我不知道如何让你的框架输出这个 Cypher。

关于spring-boot - 使用 Spring Data neo4j - SDN/ReactiveNeo4j 创建重复关系(neo4j 社区版 4.4.4),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71902174/

相关文章:

java - Spring 数据 Neo4j : do I need a index for each inherited class?

java - Spring Data Neo4j starter 和 OGM SessionFactory 中 Cannot merge node using null property value for uuid 的原因是什么?

java - 如何在 Spring Data MongoDB 中投影 $strLenCP

java - 使用docker时Turbine只能找到一台主机

neo4j - Cypher:基于公共(public)属性键 id 创建节点之间的关系

java - Neo4J 对象创建性能不佳

neo4j - 因果集群友好的实现

neo4j - 按ids通过loadAll加载递归关系时出错

java - 配置 gradle.build 将所有 spring boot 子项目构建成 jars

postgresql - Flyway - Flyway 架构迁移失败