Neo4j-如何在保存或更新相关节点时删除与另一个节点的关系

时间:2018-12-24 22:23:38

标签: neo4j cypher spring-data-neo4j neo4j-ogm

我在我的应用程序中使用Neo4j(3.4.1版)和Spring-data-neo4j(5.0.10.RELEASE)。我也在使用OGM。

我有以下领域模型(车辆和零件):

车辆类

@NodeEntity
@Data
@NoArgsConstructor
public class Vehicle {

@Id
@GeneratedValue
private Long id;

@Relationship(type = "HAS_PART", direction = Relationship.OUTGOING)
private List<Part> parts = new ArrayList<>();
}

零件类

@NodeEntity
@Data
@NoArgsConstructor
public class Part {

@Id
private String name;

public Part(String name) {
    this.name = name;
}
}

我能够为给定的parts设置vehicle,并使用spring data neo4j存储库界面将节点存储在Neo4j数据库中。

    Vehicle myVehicle = new Vehicle();

    Part brake = new Part("brake");
    Part accelerator= new Part("accelerator");
    Part clutch= new Part("clutch");

    myVehicle.setParts(Arrays.asList(brake, accelerator, clutch));
    Vehicle vehicle = vehicleRepository.save(myVehicle);
    System.out.println("vehicle = " + vehicle);

我可以使用Neo4j浏览器在数据库中同时看到VehiclePart节点,如下所示:

enter image description here

我面临的问题是在更新现有车辆时。 我正在尝试更改parts的{​​{1}}。我正在做以下事情:

vehicle

在IDE调试会话中,我可以看到 Vehicle myVehicle = vehicleRepository.findById(582L).get(); Part brake = new Part("brake"); Part accelerator= new Part("accelerator"); myVehicle.setParts(Arrays.asList(brake, accelerator)); Vehicle savedVehicle = vehicleRepository.save(myVehicle); System.out.println("vehicle = " + savedVehicle); 对象(在savedVehicle上调用save之后返回)只有两个部分:“刹车”和“加速器”。它没有“离合器”部分,就像我希望的那样。

但是,当我使用浏览器在Neo4j数据库中检查相同的车辆对象时,我看到该车辆对象仍然具有3个部分(甚至是“离合器”)。

由于我已经覆盖了节点及其关系,因此我无法理解vehicleRepository节点为何仍与clutch节点相关。另外,为什么vehicle对象与数据库中的对象不同。

有人能对此有所启发吗?另外,如何在保存/更新时删除与savedVehicle节点的HAS_PART关系。

关于, V

1 个答案:

答案 0 :(得分:1)

了解发生了什么的一个好方法是将logging.level.org.neo4j.ogm.drivers.bolt=DEBUG 添加到a​​pplication.properties。这将为您提供在日志中执行的实际密码。您会看到您的代码转换为MERGE语句,如下所示。

Request: UNWIND {rows} as row MERGE (n:`Vehicle`{name: row.props.name}) SET n=row.props RETURN row.nodeRef as ref, ID(n) as id, {type} as type with params {type=node, rows=[{nodeRef=-1, props={name=Car}}]}
Request: UNWIND {rows} as row MERGE (n:`Part`{name: row.props.name}) SET n=row.props RETURN row.nodeRef as ref, ID(n) as id, {type} as type with params {type=node, rows=[{nodeRef=-3, props={name=brake}}, {nodeRef=-5, props={name=accelerator}}, {nodeRef=-7, props={name=clutch}}]}

MERGE子句确保图形中存在模式。该模式已经存在,或者需要创建。它不会删除任何现有节点。

来到该解决方案中,有几种不同的方法可以实现您想要的,天真的解决方案是执行以下操作:

Part p = new Part("brake");
partRepository.delete(p);

但是,请注意,这将针对所有车辆节点删除名称为“ brake”的所有零件。这可能不是您一直想要的。例如您可能只想将clutch与名称为Car的车辆分开。

假设您在车辆标签上拥有name属性,则可以在代码中执行类似的操作,以从名称为Vehicle的{​​{1}}分离并删除离合器(如果您没有车辆名称,使用ID或其他唯一属性):

Car

另一种选择是在您的VehicleRepository中编写一个带有Vehicle car = vehicleRepository.findByName("Car"); for(Part p: car.getParts()){ if("clutch".equalsIgnoreCase(p.getName())){ partRepository.delete(p); } } 批注的方法,以执行以下查询的等效操作:

@Query

然后,您可以简单地从服务类中调用它。

有关示例,请参见here


编辑:添加有关删除车辆和零件之间关系的更多信息。

这可以通过在下面的vehicleRepository中编写自定义查询来完成(我假设您在Vehicle上也具有name属性,如果没有,则可以使用id代替name):

MATCH(n:Vehicle {name:"Car"})-[:HAS_PART]->(p:Part{ name:"brake"}) 
DETACH DELETE p

现在,您可以从代码中调用它,例如:

@Query("MATCH(n:Vehicle {name: {0}})-[r:HAS_PART]-(p:Part{ name:{1}}) DELETE r")
Vehicle detachPartFromVehicle(@Param("partName") String vehicleNameName, @Param("partName") String partName);

这应该导致删除vehicleRepository.detachPartFromVehicle("Car", "clutch"); 关系-HAS_PART部分将保留在图形中,但将与车辆clutch断开连接。

此外,您可以通过将其转换为IN查询来断开多个部分的连接:

Car

@Query("MATCH(n:Vehicle {name: {0}})-[r:HAS_PART]-(p:Part) WHERE p.name IN {1} DELETE r")
Vehicle detachPartFromVehicle(@Param("partName") String vehicleNameName, @Param("partNames") String[] partNames);