Head's Up! These forums are read-only. All users and content have migrated. Please join us at community.neo4j.com.
05-14-2020 06:50 AM
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
05-17-2020 11:24 PM
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
.
05-18-2020 02:10 AM
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).
05-18-2020 06:18 AM
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
05-19-2020 12:04 PM
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);
}
All the sessions of the conference are now available online