Hello. I am implementing a basic node - [relationship] - node, using a NameEntity class, which has a Relationship(type="LINK", direction = INCOMING) annotation.
The Link class has a TargetNode NameEntity.
I have a unit test which creates three nodes, with two relationships. The first time I run the unit test, the nodes and relationships are created:
The second time I run the unit test, duplicate relationships are being created:
I'm pretty new to neo4j (i'm using the community version 4.4.4).
I'm not expecting the duplicate second relationship to be created (with the same Link type). I appreciate I am not using a Version property.
Is it the default behaviour for neo4j to create a second relationship (with the same attributes). Is there a way for this second (duplicate) relationship to not be created?
I have attached copied NameEntity, and Link pojo, the unit test, and the Cypher which is run (first and second) time I run the unit test.
Any help would be appreciated.
Thanks
Miles.
NameRepository interface:
public interface NameRepository extends ReactiveNeo4jRepository<NameEntity, String>
NameEntity:
@Node("Name")
public class NameEntity {
@Id
private String name;
private String type;
@Relationship(type = "LINK", direction = INCOMING)
private Set<Link> nameLinks;
public NameEntity(final String name, final String type) {
this.name = name;
this.type = type;
}
public NameEntity() {}
Link
@RelationshipProperties
@Getter
public class Link {
@RelationshipId
private Long id;
private String type;
@TargetNode
private NameEntity nameEntity;
public Link(NameEntity nameEntity, String type) {
this.nameEntity = nameEntity;
this.type = type;
}
public Link() {}
Spring Boot first time run unit test:
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 second time run unit test:
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
Unit test
@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"));
}