Relations being overwritten using OGM (Kotlin/Micronaut)

I have a data model like this:

import org.neo4j.ogm.annotation.Id
import org.neo4j.ogm.annotation.NodeEntity

@NodeEntity
class Parent {
    @Id lateinit var name: String
    constructor(name: String) { this.name = name }
    lateinit var hasChildren: MutableSet<Child>
}

@NodeEntity
class Child {
    @Id lateinit var name: String
    constructor(name: String) { this.name = name }
    lateinit var friendOf: Child
}

The following code breaks the "friend_of" relation and I can't figure out why.

sessionFactory.openSession()?.run {
    purgeDatabase()
    var parent1 = Parent("parent1")
    save(parent1)
    var parent2 = Parent("parent2")
    save(parent2)

    var child1 = Child("child1")
    parent1.hasChildren = mutableSetOf(child1)
    save(parent1)
    var child2 = Child("child2")
    parent2.hasChildren = mutableSetOf(child2)
    save(parent2)

    child1.friendOf = child2
    save(child1)
    //Everything is good until this point. child1-[friend_of]->child2

    parent1 = load(Parent::class.java, "parent1")
    save(parent1)
    //Loading/saving parent1 does not break anything. All good until this point..

    parent2 = load(Parent::class.java, "parent2")   //tried passing depth = 2 as well
    save(parent2) //tried passing depth = 2 as well
    //loading/saving parent2 breaks and deletes the "friend_of" relation between child1 and child2

}

I have tried various depth options in load/save but no success. I have also tried clearing session and starting new transaction for each write with no luck.
Why does a reload/resave of "parent1" does not break the relation, but "parent2" breaks it?

What I assume is happening here:
The friendOf relationship is only set on child1. This means child2 has no idea about the existing (incoming) relationship to child1.
Loading and saving person1 will look from child1 to child2 :white_check_mark:
Loading and saving person2 will look from child2 to child1 :red_circle: because there is no relationship. So it will not only skip the relationship part but also takes care that there is no relationship because it assumes that this is a UNDIRECTED instead of an OUTGOING(default) relationship.
The latter seems to be a bug in Neo4j-OGM and I will have a deeper look at this.
Current workaround would be to explicitly set the intended OUTGOING relationships as such.

@Relationship(direction = Relationship.Direction.OUTGOING)
lateinit var friendOf: Child

This works! Thank you @gerrit.meier. I had assumed that both incoming and outgoing relations are retained when node is updated/merged.

FYI: We release Neo4j-OGM 3.2.24 yesterday. Release v3.2.24 · neo4j/neo4j-ogm · GitHub
The bug with the default relationship direction is now fixed.

1 Like