Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HibernateException: A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance #41198

Closed
beiertu-mms opened this issue Jun 14, 2024 · 12 comments
Labels
area/hibernate-reactive Hibernate Reactive kind/bug Something isn't working

Comments

@beiertu-mms
Copy link

beiertu-mms commented Jun 14, 2024

Describe the bug

We have a the following one-to-many entities

  • Post
      @OneToMany(mappedBy = "post", cascade = [CascadeType.ALL], orphanRemoval = true, fetch = FetchType.LAZY)
      private val _comments: MutableList<PostComment> = mutableListOf()
    
      val comments: List<PostComment> get() = _comments.toList()
    
      fun removeComment(comment: PostComment) {
          _comments.remove(comment)
          comment.post = null
      }
  • PostComment
      @ManyToOne(fetch = FetchType.LAZY, optional = false)
      @JoinColumn(name = "post_id")
      var post: Post? = null

Up until Quarkus v3.10.2, adding new PostComment to a Post works based on the test here.
But when updating the version to >=3.11.0, we got the error
A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance (github action's log).

Expected behavior

No exceptions are thrown when adding and persisting a new item to a bidirectional OneToMany entities.

Actual behavior

Failed to register a post: org.hibernate.HibernateException: A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance: de.tungbeier.panache.Post._comments
	at org.hibernate.engine.internal.Collections.processDereferencedCollection(Collections.java:98)
Full logs
Failed to register a post: org.hibernate.HibernateException: A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance: de.tungbeier.panache.Post._comments
	at org.hibernate.engine.internal.Collections.processDereferencedCollection(Collections.java:98)
	at org.hibernate.engine.internal.Collections.processUnreachableCollection(Collections.java:49)
	at org.hibernate.reactive.event.impl.AbstractReactiveFlushingEventListener.lambda$flushCollections$5(AbstractReactiveFlushingEventListener.java:237)
	at org.hibernate.engine.internal.StatefulPersistenceContext.forEachCollectionEntry(StatefulPersistenceContext.java:1328)
	at org.hibernate.reactive.event.impl.AbstractReactiveFlushingEventListener.flushCollections(AbstractReactiveFlushingEventListener.java:234)
	at org.hibernate.reactive.event.impl.AbstractReactiveFlushingEventListener.lambda$flushEverythingToExecutions$1(AbstractReactiveFlushingEventListener.java:103)
	at java.base/java.util.concurrent.CompletableFuture.uniAcceptNow(CompletableFuture.java:757)
	at java.base/java.util.concurrent.CompletableFuture.uniAcceptStage(CompletableFuture.java:735)
	at java.base/java.util.concurrent.CompletableFuture.thenAccept(CompletableFuture.java:2214)
	at java.base/java.util.concurrent.CompletableFuture.thenAccept(CompletableFuture.java:144)
	at org.hibernate.reactive.event.impl.AbstractReactiveFlushingEventListener.flushEverythingToExecutions(AbstractReactiveFlushingEventListener.java:92)
	at org.hibernate.reactive.event.impl.DefaultReactiveFlushEventListener.reactiveOnFlush(DefaultReactiveFlushEventListener.java:41)
	at org.hibernate.event.service.internal.EventListenerGroupImpl.lambda$fireEventOnEachListener$0(EventListenerGroupImpl.java:153)
	at java.base/java.util.concurrent.CompletableFuture.uniComposeStage(CompletableFuture.java:[118](https://github.com/beiertu-mms/quarkus-kotlin-playground/actions/runs/9511750499/job/26218439365?pr=1#step:4:119)7)
	at java.base/java.util.concurrent.CompletableFuture.thenCompose(CompletableFuture.java:2341)
	at java.base/java.util.concurrent.CompletableFuture.thenCompose(CompletableFuture.java:144)
	at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:153)
	at org.hibernate.reactive.session.impl.ReactiveSessionImpl.doFlush(ReactiveSessionImpl.java:982)
	at org.hibernate.reactive.session.impl.ReactiveSessionImpl.reactiveFlush(ReactiveSessionImpl.java:930)
	at io.smallrye.context.impl.wrappers.SlowContextualSupplier.get(SlowContextualSupplier.java:21)
	at io.smallrye.mutiny.operators.uni.builders.UniCreateFromCompletionStage.subscribe(UniCreateFromCompletionStage.java:24)
	at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
	at io.smallrye.mutiny.operators.uni.UniRunSubscribeOn.lambda$subscribe$0(UniRunSubscribeOn.java:27)
	at org.hibernate.reactive.context.impl.VertxContext.execute(VertxContext.java:91)
	at io.smallrye.mutiny.operators.uni.UniRunSubscribeOn.subscribe(UniRunSubscribeOn.java:25)
	at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
	at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.performInnerSubscription(UniOnItemTransformToUni.java:81)
	at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.onItem(UniOnItemTransformToUni.java:57)
	at io.smallrye.mutiny.operators.uni.builders.UniCreateFromKnownItem$KnownItemSubscription.forward(UniCreateFromKnownItem.java:38)
	at io.smallrye.mutiny.operators.uni.builders.UniCreateFromKnownItem.subscribe(UniCreateFromKnownItem.java:23)
	at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
	at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni.subscribe(UniOnItemTransformToUni.java:25)
	at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
	at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.performInnerSubscription(UniOnItemTransformToUni.java:81)
	at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.onItem(UniOnItemTransformToUni.java:57)
	at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.onItem(UniOnItemTransformToUni.java:60)
	at io.smallrye.mutiny.operators.uni.builders.UniCreateFromKnownItem$KnownItemSubscription.forward(UniCreateFromKnownItem.java:38)
	at io.smallrye.mutiny.operators.uni.builders.UniCreateFromKnownItem.subscribe(UniCreateFromKnownItem.java:23)
	at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
	at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.performInnerSubscription(UniOnItemTransformToUni.java:81)
	at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.onItem(UniOnItemTransformToUni.java:57)
	at io.smallrye.mutiny.operators.uni.builders.UniCreateFromKnownItem$KnownItemSubscription.forward(UniCreateFromKnownItem.java:38)
	at io.smallrye.mutiny.operators.uni.builders.UniCreateFromKnownItem.subscribe(UniCreateFromKnownItem.java:23)
	at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
	at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni.subscribe(UniOnItemTransformToUni.java:25)
	at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
	at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni.subscribe(UniOnItemTransformToUni.java:25)
	at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
	at io.smallrye.mutiny.operators.uni.UniOnItemTransform.subscribe(UniOnItemTransform.java:22)
	at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
	at io.smallrye.mutiny.operators.uni.UniOnItemTransform.subscribe(UniOnItemTransform.java:22)
	at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
	at io.smallrye.mutiny.operators.uni.UniOnFailureFlatMap.subscribe(UniOnFailureFlatMap.java:31)
	at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
	at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.performInnerSubscription(UniOnItemTransformToUni.java:81)
	at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.onItem(UniOnItemTransformToUni.java:57)
	at io.smallrye.mutiny.operators.uni.UniOnItemConsume$UniOnItemComsumeProcessor.onItem(UniOnItemConsume.java:43)
	at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.onItem(UniOnItemTransformToUni.java:60)
	at io.smallrye.mutiny.operators.uni.UniOperatorProcessor.onItem(UniOperatorProcessor.java:47)
	at io.smallrye.mutiny.operators.uni.UniOnItemTransform$UniOnItemTransformProcessor.onItem(UniOnItemTransform.java:43)
	at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.onItem(UniOnItemTransformToUni.java:60)
	at io.smallrye.mutiny.operators.uni.UniOnItemTransform$UniOnItemTransformProcessor.onItem(UniOnItemTransform.java:43)
	at io.smallrye.mutiny.operators.uni.UniOperatorProcessor.onItem(UniOperatorProcessor.java:47)
	at io.smallrye.mutiny.operators.uni.builders.UniCreateFromCompletionStage$CompletionStageUniSubscription.forwardResult(UniCreateFromCompletionStage.java:63)
	at java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:863)
	at java.base/java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:841)
	at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510)
	at java.base/java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:2179)
	at org.hibernate.reactive.util.async.impl.AsyncTrampoline$TrampolineInternal.unroll(AsyncTrampoline.java:131)
	at org.hibernate.reactive.util.async.impl.AsyncTrampoline$TrampolineInternal.lambda$unroll$0(AsyncTrampoline.java:[126](https://github.com/beiertu-mms/quarkus-kotlin-playground/actions/runs/9511750499/job/26218439365?pr=1#step:4:127))
	at java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:863)
	at java.base/java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:841)
	at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510)
	at java.base/java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:2179)
	at io.vertx.core.Future.lambda$toCompletionStage$3(Future.java:581)
	at io.vertx.core.impl.future.FutureImpl$4.onSuccess(FutureImpl.java:176)
	at io.vertx.core.impl.future.FutureBase.emitSuccess(FutureBase.java:66)
	at io.vertx.core.impl.future.FutureImpl.tryComplete(FutureImpl.java:259)
	at io.vertx.sqlclient.impl.QueryResultBuilder.tryComplete(QueryResultBuilder.java:88)
	at io.vertx.sqlclient.impl.QueryResultBuilder.tryComplete(QueryResultBuilder.java:32)
	at io.vertx.core.Promise.complete(Promise.java:66)
	at io.vertx.core.Promise.handle(Promise.java:51)
	at io.vertx.core.Promise.handle(Promise.java:29)
	at io.vertx.core.impl.future.FutureImpl$4.onSuccess(FutureImpl.java:176)
	at io.vertx.core.impl.future.FutureBase.emitSuccess(FutureBase.java:66)
	at io.vertx.core.impl.future.FutureImpl.tryComplete(FutureImpl.java:259)
	at io.vertx.core.impl.future.PromiseImpl.onSuccess(PromiseImpl.java:49)
	at io.vertx.core.impl.future.PromiseImpl.handle(PromiseImpl.java:41)
	at io.vertx.sqlclient.impl.TransactionImpl.lambda$wrap$0(TransactionImpl.java:72)
	at io.vertx.core.impl.future.FutureImpl$4.onSuccess(FutureImpl.java:176)
	at io.vertx.core.impl.future.FutureBase.lambda$emitSuccess$0(FutureBase.java:60)
	at io.netty.util.concurrent.AbstractEventExecutor.runTask(AbstractEventExecutor.java:173)
	at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:166)
	at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:470)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:569)
	at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.base/java.lang.Thread.run(Thread.java:1583)

How to Reproduce?

git clone [email protected]:beiertu-mms/quarkus-kotlin-playground.git
cd quarkus-kotlin-playground
./mvnw clean verify

Output of uname -a or ver

Linux 6.9.4-arch1-1 x86_64 GNU/Linux

Output of java -version

openjdk version "22" 2024-03-19

Quarkus version or git rev

3.11.2

Build tool (ie. output of mvnw --version or gradlew --version)

Apache Maven 3.9.6 (bc0240f3c744dd6b6ec2920b3cd08dcc295161ae)

Additional information

No response

@beiertu-mms beiertu-mms added the kind/bug Something isn't working label Jun 14, 2024
Copy link

quarkus-bot bot commented Jun 14, 2024

/cc @geoand (kotlin)

@geoand geoand added the area/hibernate-orm Hibernate ORM label Jun 14, 2024
@geoand
Copy link
Contributor

geoand commented Jun 14, 2024

cc @yrodiere

@yrodiere
Copy link
Member

yrodiere commented Jun 14, 2024

Thanks for reporting.

I see you're using Hibernate Reactive, but given the nature of the problem, it's more likely a Hibernate ORM issue.

The Kotlin part makes me uneasy; I suspect your _comments.toList() may be involved in the problem if it returns a different list instance every time... So it's possible the failure is actually legitimate. I'm not very familiar with Kotlin though.

Can you reproduce this with https://github.com/hibernate/hibernate-test-case-templates/blob/main/orm/hibernate-orm-6/src/test/java/org/hibernate/bugs/QuarkusLikeORMUnitTestCase.java? Ideally in pure Java?

If so, I would suggest reporting directly through Hibernate's Jira instance, and leaving a link to that Jira here.

@beiertu-mms
Copy link
Author

Thank you @yrodiere for the quick reply. Will try it out with pure Java.

@beiertu-mms
Copy link
Author

@yrodiere I have refactored the code to Java, and it looks like the issue occured when I read an entity first before updating it.
So this test without a read works, but the test with a read will fail.

Strangely, switching back to Quarkus v3.10.2 will make both tests run successfully.

@yrodiere
Copy link
Member

yrodiere commented Jun 18, 2024

Thanks @beiertu-mms .

So, from what I see in your reproducer, this is how things go wrong:

  1. You have a Post in your persistence context, with its comments association set to some persistent collection, containing one `Post.
  2. You run a query with a join fetch on comments: from Post p left join fetch p.comments c where p.title = :title order by p.id
  3. When you run that query, for some reason, Hibernate ORM/Reactive sets the comments field to a different persistent collection, but leaves the previous one in the persistence context.
  4. When a flush finally happens, Hibernate ORM/Reactive finds out the initial persistent collection is no longer referenced anywhere, and you get this exception:
2024-06-18 13:21:04,314 ERROR [de.tun.par.PostService] (vert.x-eventloop-thread-1) Failed to register a post: org.hibernate.HibernateException: A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance: de.tungbeier.paranche.Post.comments
	at org.hibernate.engine.internal.Collections.processDereferencedCollection(Collections.java:98)
	at org.hibernate.engine.internal.Collections.processUnreachableCollection(Collections.java:49)
	at org.hibernate.reactive.event.impl.AbstractReactiveFlushingEventListener.lambda$flushCollections$5(AbstractReactiveFlushingEventListener.java:237)
	at org.hibernate.engine.internal.StatefulPersistenceContext.forEachCollectionEntry(StatefulPersistenceContext.java:1328)
	at org.hibernate.reactive.event.impl.AbstractReactiveFlushingEventListener.flushCollections(AbstractReactiveFlushingEventListener.java:234)
	at org.hibernate.reactive.event.impl.AbstractReactiveFlushingEventListener.lambda$flushEverythingToExecutions$1(AbstractReactiveFlushingEventListener.java:103)
	at java.base/java.util.concurrent.CompletableFuture.uniAcceptNow(CompletableFuture.java:757)
	at java.base/java.util.concurrent.CompletableFuture.uniAcceptStage(CompletableFuture.java:735)
	at java.base/java.util.concurrent.CompletableFuture.thenAccept(CompletableFuture.java:2214)
	at java.base/java.util.concurrent.CompletableFuture.thenAccept(CompletableFuture.java:144)
	at org.hibernate.reactive.event.impl.AbstractReactiveFlushingEventListener.flushEverythingToExecutions(AbstractReactiveFlushingEventListener.java:92)
	at org.hibernate.reactive.event.impl.DefaultReactiveFlushEventListener.reactiveOnFlush(DefaultReactiveFlushEventListener.java:41)
	at org.hibernate.event.service.internal.EventListenerGroupImpl.lambda$fireEventOnEachListener$0(EventListenerGroupImpl.java:153)
	at java.base/java.util.concurrent.CompletableFuture.uniComposeStage(CompletableFuture.java:1187)
	at java.base/java.util.concurrent.CompletableFuture.thenCompose(CompletableFuture.java:2341)
	at java.base/java.util.concurrent.CompletableFuture.thenCompose(CompletableFuture.java:144)
	at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:153)
	at org.hibernate.reactive.session.impl.ReactiveSessionImpl.doFlush(ReactiveSessionImpl.java:982)
	at org.hibernate.reactive.session.impl.ReactiveSessionImpl.reactiveFlush(ReactiveSessionImpl.java:930)
	at io.smallrye.context.impl.wrappers.SlowContextualSupplier.get(SlowContextualSupplier.java:21)
	at io.smallrye.mutiny.operators.uni.builders.UniCreateFromCompletionStage.subscribe(UniCreateFromCompletionStage.java:24)
	at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
	at io.smallrye.mutiny.operators.uni.UniRunSubscribeOn.lambda$subscribe$0(UniRunSubscribeOn.java:27)
	at org.hibernate.reactive.context.impl.VertxContext.execute(VertxContext.java:91)
	at io.smallrye.mutiny.operators.uni.UniRunSubscribeOn.subscribe(UniRunSubscribeOn.java:25)
        [...]

This actually looks like a bug in Hibernate Reactive... I wouldn't expect a new persistent collection to be created in case of join fetch fetching a collection that is already in the persistence context, but if it is, I would at least expect the previous persistent collection to be removed from the persistence context.

@DavideD can you please confirm and file a bug upstream?

EDIT: Also, this is not specific to Kotlin.

@DavideD
Copy link
Contributor

DavideD commented Jun 19, 2024

Yes, it looks like a bug.
I've created this: hibernate/hibernate-reactive#1942

@flyinfish
Copy link

does not seem explicitly problem in hibernate-reactive, problem occurs in traditional-hibernate too

io.quarkus:quarkus-hibernate-orm:3.12.2
org.hibernate.orm:hibernate-core:6.5.2.Final

@yrodiere
Copy link
Member

yrodiere commented Jul 19, 2024

Similar issue on Hibernate ORM -- perhaps the same root cause, perhaps not -- https://hibernate.atlassian.net/browse/HHH-18389. On Quarkus: #7462

@MarcelEdmundFranke
Copy link

MarcelEdmundFranke commented Jul 23, 2024

I am experiencing a comparable or identical issue. Following the upgrade from Spring Boot 3.2.x to 3.3.x, I encountered the following problem: org.hibernate.HibernateException: A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance.

Hibernate ORM core version 6.5.2.Final

@MarcelEdmundFranke
Copy link

MarcelEdmundFranke commented Jul 23, 2024

I reverted to Hibernate version 6.4.9 Final, and now it is functioning correctly again.

FYI @yrodiere

@beiertu-mms
Copy link
Author

This seems to have been fixed with Quarkus version >= 3.11.2.
At least my test setup here beiertu-mms/quarkus-kotlin-playground#1 is green again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/hibernate-reactive Hibernate Reactive kind/bug Something isn't working
Projects
None yet
Development

No branches or pull requests

6 participants