Head's Up! These forums are read-only. All users and content have migrated. Please join us at community.neo4j.com.
04-05-2021 10:15 AM
Kotlin 1.4.31
Spring Framework Boot 2.4.4
Desktop 4.2.4
also see GitHub - Wayne-P/graph: Kotlin Neo4j Graph Issue
Possibly related to NullPointerException when persisting Kotlin data class · Issue #2141 · spring-projects/spring-data-n... ,
possibly related to Return related objects with ids set after save · Issue #2148 · spring-projects/spring-data-neo4j · G... ,
probably related to something I am overlooking owing to an Easter hangover.
So we have three classes imaginatively labelled A, B & C
@Node ("NODE_A")
data class A constructor(
@Id @GeneratedValue val id: Long? = null, val aName: String, @Relationship(type = "A_TO_B_REL") val b: B, @Relationship(type = "A_TO_C_REL") val c: C
)
@Node ("NODE_B")
data class B constructor(
@Id @GeneratedValue val id: Long? = null, val bName:String, @Relationship(type = "B_TO_C_REL") val cList: List<C>
)
@Node("NODE_C")
data class C constructor(
@Id @GeneratedValue val id: Long? = null, val cName: String
)
So, roughly A has a B and a C.
B has a list of C .
So far, so good.
The application code ...
@Transactional
@SpringBootApplication
class GraphApplication {
@Bean
fun init(aRepository: ARepository, bRepository: BRepository, cRepository: CRepository): CommandLineRunner {
return CommandLineRunner {
val c1 = C(cName = "c1")
val c2 = C(cName = "c2")
val b1 = B(bName = "b1", cList = listOf(c1, c2))
val a1 = A(aName = "a1", b = b1, c = c1)
aRepository.deleteAll()
bRepository.deleteAll()
cRepository.deleteAll()
aRepository.save<A>(a1)
}
}
}
fun main(args: Array<String>) {
runApplication<GraphApplication>(*args)
}
Now curiously, repeated efforts to execute this code give different results.
Sometimes, an IllegalStateExcexception from the save attempt of
java.lang.IllegalStateException: Failed to execute CommandLineRunner
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:809) ~[spring-boot-2.4.4.jar:2.4.4]
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:790) ~[spring-boot-2.4.4.jar:2.4.4]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:333) ~[spring-boot-2.4.4.jar:2.4.4]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1313) ~[spring-boot-2.4.4.jar:2.4.4]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1302) ~[spring-boot-2.4.4.jar:2.4.4]
at aoni.graph.GraphApplicationKt.main(GraphApplication.kt:39) ~[main/:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) ~[spring-boot-devtools-2.4.4.jar:2.4.4]
Caused by: java.util.NoSuchElementException: No value present
at java.base/java.util.Optional.get(Optional.java:148) ~[na:na]
Other times, the code runs without exception to produce two c1s with different ids
I appreciate that work is still being done in 2148 to ensure that ids of subcomponents are correctly returned in response to a save, but will this work lead to one c1 being created here ?
Or, as I suspect, should I be blaming the acetyldehyde here ?
Many thanks for any enlightenment.
04-12-2021 03:06 PM
for reference, I have now created a related github issue for this matter
https://github.com/spring-projects/spring-data-neo4j/issues/2223
04-14-2021 03:37 AM
Thanks for asking and reporting the problem on GitHub.
Quick update to avoid noisy talk on the issue. You are 100% correct with the observation of the faulty behaviour. There are several things that come together:
What happens here is
in the exceptional case we traverse from
A to C1 first and mark the C1 as processed (correct)
A to B to C1 but since we are starting again from A over B to C1 this C1 is the "old" one but seen as already processed because the id will be set later. SDN decides now to load the C1 from the database because it should be existing but it does not have any id to query for.
In the duplicate phase the path A - B - C1 gets processed first and C1 gets (again) registered. But now the loop for A's relationships is still in the state that C1 was never be touched and creates happy a new one.
The order is random because we get the fields from a Set-based collection from the Spring Data commons library. So in the end there are two bugs for your scenario I have to fix now
Again thanks for reporting and helping us to make SDN more stable.
All the sessions of the conference are now available online