0

Say I have nodes of types A, B and C, and I have the following graph: enter image description here

@NodeEntity
data class A(
    @Id val id: String? = null,
    @Relationship(type = "HAS_B")
    val b: MutableSet<B> = mutableSetOf<B>()
)

@RelationshipEntity(type = "HAS_B")
data class HasB @JvmOverloads constructor(
    @Id @GeneratedValue val id: Long? = null,
    @StartNode val start: A = A(),
    @EndNode val end: B = B()
)

@NodeEntity
data class B(
    @Id val id: String? = null,
    @Relationship(type = "HAS_C")
    val c: MutableSet<C> = mutableSetOf<C>()
)

...

My goal is to load the node A, together with the connected B and C nodes.

Currently (in Kotlin code) I am doing session.load(A::class.java, "a1", -1), which uses this implementation: <T,ID extends Serializable> T load(Class<T> type, ID id, int depth) (from here)

Supposedly, with depth = -1, this should load node A together with all its connected nodes. However, it seems to only load the node A.

What is causing this issue, and how to fix it?

Patrick Chen
  • 157
  • 4
  • I deleted my answer, as it turned out the OGM code is too involved for me to give a confident answer within a reasonable amount of time. – cybersam Jul 12 '23 at 22:35
  • @cybersam I got an answer from neo4j staff and posted an answer. Check it out if you're interested – Patrick Chen Jul 14 '23 at 07:54

1 Answers1

0

Note: I have edited the question to better reflect the essence of it. This answer summarizes the learnings from https://github.com/neo4j/neo4j-ogm/issues/951, which is mainly contributed by https://stackoverflow.com/users/2650436/meistermeier

What's causing the issue is:

@Relationship(type = "HAS_B")
val b: MutableSet<B> = mutableSetOf<B>()

In order for OGM to go from node entity A to relationship entity HasB, the @Relationship should annotate a variable that directly refers to the relationship entity itself, instead of node entity B (i.e. the node entity it connects A to).

Solution:

@NodeEntity
data class A(
    @Id val id: String? = null,
    @Relationship(type = "HAS_B")
    var b: MutableSet<HasB> = mutableSetOf()
)

@RelationshipEntity(type = "HAS_B")
class HasB @JvmOverloads constructor(
    @Id @GeneratedValue val id: Long? = null,
    @StartNode val start: A = A(),
    @EndNode val end: B = B()
) {
    override fun toString(): String {
        return "HasB(id=$id, end=$end)"
    }
}

@NodeEntity
data class B(
    @Id val id: String? = null,
    @Relationship(type = "HAS_C")
    val c: MutableSet<C> = mutableSetOf()
)

@NodeEntity
data class C(
    @Id val id: String? = null
)
Patrick Chen
  • 157
  • 4