OGM @Relationship not working as expected

Hi,
I have an object that references another object

@NodeEntity
public class Check {

@Relationship(type="PART_OF", direction=Relationship.OUTGOING)
protected CheckGroup associatedGroup = null;

As the application executes the user can bind a Check instance to a different CheckGroup instance and save the graph in memory back into Neo4j via the OGM. I expected, because "associatedGroup" is a single CheckGroup instance, that OGM would remove the existing relationship between the appropriate Check and CheckGroup instances and replace with the new relationship. i.e. if Check1 had a relationship to CheckGroup1 and the user wanted Check1 to have a relationship with CheckGroup2 then i expected that OGM would see that the existing relationship between Check1 and CheckGroup1 in the database had been replaced by a new relationship established between Check1 and CheckGroup2 in memory and would correspondingly remove the Check1-CheckGroup1 relationship in the database and create a new relationship Check1-CheckGroup2 in the database.
The attached graph screen shots shows otherwise.
Before User rebinds


After User has rebound

I am obviously missing something but i do not see what.

This is just a guess: Do you maybe don't load the Check with its CheckGroup in the same session / transaction?
To make Neo4j-OGM aware of the already existing relationship, it needs to fetch (and cache) the data. Also the relationships will get cached and it can then also delete the old one when persisting the Check.

Hi,

As per the advice within section 3.7.1 Session Configuration the lifetimes of the sessions has been chosen at the 'unit of work' granularity rather than the fetch-update-save lifetime.

Restoration from database

The Check & CheckGroup are definately restored from the database to memory using the same Session.
The restore is achieved using sessionObj.loadAll(CheckEntity.class, -1). CheckEntity is the base class from which Check and CheckGroup are ultimately derived.
The Restoration works fine.

Persisting to Database.
A different Sessions is used to control the persisting. Persisting involves persisting the root 'dirty' object and all its related objects. For example, the persist is achieved for Check using anotherSessionObj.save(Check.class, -1).

The persisting step with the new session is the problem. It has to use also the session that has loaded the graph.
A unit of work could be considered as

  • load
  • modify
  • persist

Gerrit is correct. The answer is to first query for the ones you want to delete in a session, and then in that same session, set the relationship to null / delete it from the list. While also in that same session, add the new one you need.

  @Test
  @Transactional
  public void deleteOneRelationshipEdge() {
    setupData();
    final Optional<Student> aStudentWithTwoEdges = studentRepository.findById("naturalKey");
    assertEquals(2, aStudentWithTwoEdges.get().getEnrolledIn().size(), "should have 2 courses now");
    aStudentWithTwoEdges.get().getEnrolledIn().remove(0); //delete one edge
    studentRepository.save(aStudentWithTwoEdges.get());
    
    final Optional<Student> actualStudent = studentRepository.findById("naturalKey");
    assertEquals(1, actualStudent.get().getEnrolledIn().size(), "should have 1 course now");
  }

private void setupData(){
Student expected = new Student();
    expected.setFirstName("John");
    expected.setLastName("Carter");
    expected.setKey("naturalKey");

    List<EnrolledIn> enrollment = new ArrayList<>();
    EnrolledIn enrolledIn = new  EnrolledIn()
        .setCourse(new Course()
            .setCourseName("neo4j101")
            .setKey("n4j101-jan2020"))
        .setSemester("Jan-2020")
        .setStudent(expected);
    EnrolledIn enrolledIn2 = new  EnrolledIn()
        .setCourse(new Course()
            .setCourseName("java101")
            .setKey("java101-2020"))
        .setSemester("Jan-2020")
        .setStudent(expected);
    enrollment.add(enrolledIn);
    enrollment.add(enrolledIn2);
    expected.setEnrolledIn(enrollment);

    final Student actual = studentRepository.save(expected);
}