Description
When you have an entity with a composite identifier that has an association to another entity (e.g., like in Example 134. IdClass with @ManyToOne
in the Hibernate User Guide) then any attempt to query such entities will result in an exception.
So given for example the following entities:
@Entity
public class GroceryList implements Serializable {
@Id @GeneratedValue
private Long id;
@OneToMany(mappedBy = "groceryList", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private List<ShoppingItem> shoppingItems;
}
@Entity
@IdClass(ShoppingItem.ShoppingItemId.class)
public class ShoppingItem implements Serializable {
@Id
@ManyToOne
@JoinColumn(name = "grocerylistid")
private GroceryList groceryList;
@Id
private String itemName;
private int itemCount;
public static class ShoppingItemId implements Serializable {
private String itemName;
private GroceryList groceryList;
}
}
When you try to run a simple query like this:
FROM ShoppingItem WHERE grocerylistid = :id
Then you will receive the following exception:
2022-09-06 14:32:55,518 ERROR [org.hib.rea.errors] (vert.x-eventloop-thread-2) HR000057: Failed to execute statement [select shoppingit0_.grocerylistid as groceryl3_1_, shoppingit0_.itemName as itemname1_1_, shoppingit0_.itemCount as itemcoun2_1_ from ShoppingItem shoppingit0_ where grocerylistid=$1]: could not execute query: java.util.concurrent.CompletionException: org.hibernate.reactive.event.impl.UnexpectedAccessToTheDatabase: Unexpected access to the database
at java.base/java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:314)
at java.base/java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:319)
at java.base/java.util.concurrent.CompletableFuture$UniCompose.tryFire(CompletableFuture.java:1081)
at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:506)
at java.base/java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:2073)
at io.vertx.core.Future.lambda$toCompletionStage$2(Future.java:360)
at io.vertx.core.impl.future.FutureImpl$3.onSuccess(FutureImpl.java:141)
at io.vertx.core.impl.future.FutureBase.emitSuccess(FutureBase.java:60)
at io.vertx.core.impl.future.FutureImpl.tryComplete(FutureImpl.java:211)
at io.vertx.core.impl.future.PromiseImpl.tryComplete(PromiseImpl.java:23)
at io.vertx.sqlclient.impl.QueryResultBuilder.tryComplete(QueryResultBuilder.java:102)
at io.vertx.sqlclient.impl.QueryResultBuilder.tryComplete(QueryResultBuilder.java:35)
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$3.onSuccess(FutureImpl.java:141)
at io.vertx.core.impl.future.FutureBase.emitSuccess(FutureBase.java:60)
at io.vertx.core.impl.future.FutureImpl.tryComplete(FutureImpl.java:211)
at io.vertx.core.impl.future.PromiseImpl.tryComplete(PromiseImpl.java:23)
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$3.onSuccess(FutureImpl.java:141)
at io.vertx.core.impl.future.FutureBase.lambda$emitSuccess$0(FutureBase.java:54)
at io.netty.util.concurrent.AbstractEventExecutor.runTask(AbstractEventExecutor.java:174)
at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:167)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:470)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:503)
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:829)
Caused by: org.hibernate.reactive.event.impl.UnexpectedAccessToTheDatabase: Unexpected access to the database
at org.hibernate.reactive.event.impl.DefaultReactiveLoadEventListener.onLoad(DefaultReactiveLoadEventListener.java:108)
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:118)
at org.hibernate.internal.SessionImpl.fireLoadNoChecks(SessionImpl.java:1231)
at org.hibernate.internal.SessionImpl.internalLoad(SessionImpl.java:1096)
at org.hibernate.type.EntityType.resolveIdentifier(EntityType.java:706)
at org.hibernate.type.EntityType.resolve(EntityType.java:465)
at org.hibernate.type.ManyToOneType.resolve(ManyToOneType.java:265)
at org.hibernate.type.EntityType.resolve(EntityType.java:458)
at org.hibernate.type.ComponentType.resolve(ComponentType.java:695)
at org.hibernate.loader.Loader.extractKeysFromResultSet(Loader.java:881)
at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:735)
at org.hibernate.loader.Loader.getRowsFromResultSet(Loader.java:1047)
at org.hibernate.reactive.loader.hql.impl.ReactiveQueryLoader.getRowsFromResultSet(ReactiveQueryLoader.java:223)
at org.hibernate.reactive.loader.ReactiveLoaderBasedResultSetProcessor.reactiveExtractResults(ReactiveLoaderBasedResultSetProcessor.java:73)
at org.hibernate.reactive.loader.hql.impl.ReactiveQueryLoader$1.reactiveExtractResults(ReactiveQueryLoader.java:72)
at org.hibernate.reactive.loader.ReactiveLoader.reactiveProcessResultSet(ReactiveLoader.java:145)
at org.hibernate.reactive.loader.ReactiveLoader.lambda$doReactiveQueryAndInitializeNonLazyCollections$0(ReactiveLoader.java:77)
at java.base/java.util.concurrent.CompletableFuture$UniCompose.tryFire(CompletableFuture.java:1072)
... 29 more
Similarly, a LEFT JOIN FETCH
doesn't work either. The only way I was able to work around this issue is to use an Entity Graph to fetch GroceryList
+ ShoppingItem
. And of course, as soon as you get rid of the @IdClass
, it also works.
Full Reproducer: https://github.com/markusdlugi/hr-composite-id-reproducer
Reproducer uses Hibernate Reactive Panache, but it is also reproducible with vanilla HR.
Tested with Quarkus 2.12.0.Final and Hibernate Reactive 1.1.7.Final.