我正在使用Spring Data Neo4j 4。假设我有 Person 类型的节点,相应的 Java 域对象是
@NodeEntity
public class Person {
@GraphId private Long id;
private String name;
private String lastName;
@Relationship(type = "KNOWS")
Set<Person> myTypes;
}
我正在尝试创建一个类似"
约翰-知道->乔治和约翰-知道->安。 安-知道->挖
'。以下是我设置域对象和持久化的方式。
Person john = new Person("John","P");
Person george = new Person("George","B");
Person Ann = new Person("Ann","M");
Person Dug = new Person("Dug","S");
Set<Person> Persons= new HashSet<Person>();
Set<Person> Persons1= new HashSet<Person>();
Persons1.add(Dug);
Ann.setMyTypes(Persons1);
Persons.add(george);
Persons.add(Ann);
john.setMyTypes(Persons);
personRepository.save(john);
personRepository.save(george);
personRepository.save(Ann);
personRepository.save(Dug);
但令我惊讶的是,只有节点是在没有关系的情况下创建的.我正在调试这个,在这一行之后 personRepository.save(john)创建了具有关系的节点,但在随后的保存期间,所有关系都被删除了。下面是日志中打印的内容,并清楚地表明关系已删除。
Request: UNWIND {rows} as row CREATE (n:`Person`) SET n=row.props RETURN row.nodeRef as ref, ID(n) as id, row.type as type with params {rows=[{nodeRef=-2115049587, type=node, props={name=George, attrib=B}}, {nodeRef=-341599918, type=node, props={name=Ann, attrib=M}}, {nodeRef=-737678933, type=node, props={name=John, attrib=P}}, {nodeRef=-1025122203, type=node, props={name=Dug, attrib=S}}]}
Request: UNWIND {rows} as row MATCH (startNode) WHERE ID(startNode) = row.startNodeId MATCH (endNode) WHERE ID(endNode) = row.endNodeId MERGE (startNode)-[rel:`KNOWS`]->(endNode) RETURN row.relRef as ref, ID(rel) as id, row.type as type with params {rows=[{relRef=-1807300324, endNodeId=2448, type=rel, startNodeId=2450}, {relRef=-272508006, endNodeId=2451, type=rel, startNodeId=2449}, {relRef=-845107952, endNodeId=2449, type=rel, startNodeId=2450}]}
Request: UNWIND {rows} as row MATCH (startNode) WHERE ID(startNode) = row.startNodeId MATCH (endNode) WHERE ID(endNode) = row.endNodeId MATCH (startNode)-[rel:`KNOWS`]->(endNode) DELETE rel with params {rows=[{endNodeId=2448, startNodeId=2450}]}
Request: UNWIND {rows} as row MATCH (startNode) WHERE ID(startNode) = row.startNodeId MATCH (endNode) WHERE ID(endNode) = row.endNodeId MATCH (startNode)-[rel:`KNOWS`]->(endNode) DELETE rel with params {rows=[{endNodeId=2449, startNodeId=2450}]}
Request: UNWIND {rows} as row MATCH (startNode) WHERE ID(startNode) = row.startNodeId MATCH (endNode) WHERE ID(endNode) = row.endNodeId MATCH (startNode)-[rel:`KNOWS`]->(endNode) DELETE rel with params {rows=[{endNodeId=2451, startNodeId=2449}]}
不知道我哪里出了问题,或者这就是它应该工作的方式
这是 OGM 的关系不明确的情况,因为它们存在于同一类型之间,但存在于特定方向上。
(john)-[:KNOWS]->(george)
也暗示乔治应该有一个来自约翰的传入关系,但领域模型没有反映这一点。正如您所注意到的,在随后的保存中,关系将被删除,因为映射器由于歧义而无法确定要保留的内容。
当您在相同类型的实体之间具有这些关系时,明确关系方向是解决方案。在您的情况下,从一个人到另一个人的关系总是在传出方向上,因此添加这样的方向可以清楚地表明 OGM 不必担心相同类型的传入关系。
@Relationship(type = "KNOWS", direction = "OUTGOING")
Set<Person> myTypes;
此外,您不必拯救每个人 - 在您的示例中,保存约翰就足够了,因为 OGM 可以从约翰遍历到乔治和安,从而到达 Dug。
我认为问题出在您保存 Person 对象的方式上。一种解决方案是先保存人员对象。然后添加关系并仅重新保存已在其中添加关系的实体,而不重新保存添加的实体。
例如
Person john = new Person("John","P");
Person Ann = new Person("Ann","M");
Set<Person> Persons= new HashSet<Person>();
Persons.add(Ann);
john.setMyTypes(Persons);
personRepository.save(john);
以上将拯救约翰和安,并将在他们之间建立"知道"的关系。没必要再救安了。
如果您尝试再次保存 Ann,请在上述代码之后
personRepository.save(Ann);
该关系将被删除,因为 neo4j 会将其视为没有任何关系的实体,因为之前创建 Ann 对象时该关系不存在