我正在使用 NameEntity
类实现一个基本节点 - [relationship] - 节点,该类具有 Relationship(type="LINK", Direction = INCOMING)
注释。
Link
类有一个 @TargetNode
NameEntity
。
我有一个单元测试,它创建三个节点,具有两个关系。我第一次运行单元测试时,会创建节点和关系:
我第二次运行单元测试时,正在创建重复的关系:
我对 neo4j 还很陌生(我使用的是社区版本 4.4.4)。
我不希望创建重复的第二个关系(具有相同的Link
类型)。我很高兴我没有使用 Version 属性。
这是 Neo4j 创建第二个关系(具有相同属性)的默认行为吗?有没有办法不创建第二个(重复)关系?
我已附加复制的 NameEntity
和 Link
pojo、单元测试以及我运行单元测试时(第一次和第二次)运行的 Cypher。
我“认为”解决方案可能是覆盖 equals
和 hashCode
,但非常欢迎提供具体的示例。我还没找到。
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/