Neo4j - how to delete relationship with another node on save or update of a related node


(Varun85 Jobs) #1

I am using Neo4j (version 3.4.1) and Spring-data-neo4j (5.0.10.RELEASE) in my application. I am also using OGM.

I have the following domain model (Vehicle and Part):

Vehicle class

@NodeEntity
@Data
@NoArgsConstructor
public class Vehicle {

@Id
@GeneratedValue
private Long id;

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

Part class

@NodeEntity
@Data
@NoArgsConstructor
public class Part {

@Id
private String name;

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

I am able to set parts for a given vehicle and store the nodes in the Neo4j database using a spring data neo4j repository interface.

    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);

I am able to see both the Vehicle and Part nodes in the database using Neo4j browser, something as shown below :

enter image description here

The problem that I am facing is during updating of the existing vehicle.
I am trying to change the parts that the vehicle has. I am doing as follows:

    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);

In the IDE debug session, I can see that the savedVehicle object (returned after calling save on vehicleRepository) has only 2 parts "brake" and "accelerator". It doesn't have "clutch" part in it, the way I want it to be.

However, when I check the same vehicle object in the Neo4j database using browser, I see that the vehicle object still has 3 parts (even the "clutch").

I am not able to understand why is clutch node still related to the vehicle node as I have overwritten the node and its relationship. Also why is the savedVehicle object different from one in the database.

Is someone able to shed some light on this? Also how can I remove the HAS_PART relationship with clutch node on save/update.

Regards,
V


(Gerrit Meier) #2

From what you describe I assume that your problem is a result of missing transactions.

The first code part looks good. You are creating the vehicle, put every part on it and save it.
Let's take a closer look on the load and modification part:

Vehicle myVehicle = vehicleRepository.findById(582L).get();
will result in a myVehicle (let's call this V1) with the previously saved parts (incl. the clutch).

Setting the "new" parts will replace the list in myVehicle and (before) saving it will result in myVehicle V2.

Before the save against Neo4j starts, Neo4j-OGM will check what modification where made to the objects.
And here comes the point where I got my assumption from:

If the whole block does not happen within one transaction, Neo4j-OGM will assume that V2 has to get a complete rewrite. It knows that it is already in the database because it has an id set but does not know the previous state.
Just looking at the relationships now, OGM sees two new ones that need to get created and as a result create them both and set myVehicle in the Java world to this new state.
There was no chance for Neo4j-OGM to get the information that there was a third relationship before in V1.

Technical note: every operation in Spring Data Neo4j will spawn a new Session with its own cache. When a explicit transaction (@Transactional annotation on the methods) is defined it will work in the same Session for all operations in the method block.

The only thing that confuses me is that you are "only" seeing two parts instead of duplicated brake and accelerator.