In a project using Spring Data Neo4j 3.2, I have a model which looks like:
@NodeEntity
public abstract class A {
@GraphId
public Long id;
@Indexed(unique = true)
public Long technicalId;
}
@NodeEntity
public class B extends A {}
@NodeEntity
public class C extends A {}
I missed the paragraph in the documentation talking about the default merge feature, and we ran into the following situation without getting an exception:
B b = new B();
b.technicalId = 42;
neo4jTemplate.save(b);
// I now have Node[1] in Neo4j with the following labels: B, _B, A
C c = new C();
c.technicalId = 42;
neo4jTemplate.save(c);
// No exception and Node[1] now has the following labels: B, _B, A, C, _C
So OK, the situation can be avoided by:
either using instance-based indices:
@NodeEntity public abstract class A { @GraphId public Long id; @Indexed(unique = true, level = Level.INSTANCE) public Long technicalId; }
or using
failOnDuplicate
(though it's not mentioned in the documentation, even for 3.3, but I found it here and here) which avoids creating 3 indices instead of 1, so less I/Os on writes and less disk space used:@NodeEntity public abstract class A { @GraphId public Long id; @Indexed(unique = true, failOnDuplicate = true) public Long technicalId; }
However, isn't it a bug that the default behavior will change the nature of the node (when there's a class hierarchy involved) and create a mix of labels which could prevent the instantiation of an entity? I mean the node now has 2 underscore-prefixed labels: n:B:_B:A:C:_C
, because the 2 Cypher queries that were executed were:
MERGE (n:`A` {`technicalId`: {value}})
ON CREATE SET n={props} SET n:SupplierCompany
return n
// params {value=42, props={technicalId=42}}
match (n)
where id(n)={nodeId}
set n:`A`:`C`:`_C`
// params {nodeId=1}
Should I raise an issue with a test case on the SDN JIRA or github?