迁移到 Quarkus 3.14 和 Hibernate 6 后,自定义查询投影停止工作。
我还有很多例子,但都归结为这个例外以及自定义查询和聚合类投影的组合。
我得到的异常:
org.hibernate.InstantiationException: Cannot instantiate query result type 'xx.domain.UnitDetails' due to: xx.domain.BusinessUnitDetails.<init>(java.lang.String,xx.domain.BusinessUnitType,java.lang.Integer)
at org.hibernate.sql.results.internal.RowTransformerConstructorImpl.<init>(RowTransformerConstructorImpl.java:42)
at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.determineRowTransformer(ConcreteSqmSelectQueryPlan.java:315)
at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.<init>(ConcreteSqmSelectQueryPlan.java:96)
at org.hibernate.query.sqm.internal.AbstractSqmSelectionQuery.buildConcreteQueryPlan(AbstractSqmSelectionQuery.java:277)
at org.hibernate.query.sqm.internal.AbstractSqmSelectionQuery.buildConcreteQueryPlan(AbstractSqmSelectionQuery.java:261)
at org.hibernate.query.sqm.internal.AbstractSqmSelectionQuery.buildSelectQueryPlan(AbstractSqmSelectionQuery.java:247)
at org.hibernate.query.internal.QueryInterpretationCacheStandardImpl.resolveSelectQueryPlan(QueryInterpretationCacheStandardImpl.java:83)
at org.hibernate.query.sqm.internal.SqmSelectionQueryImpl.resolveQueryPlan(SqmSelectionQueryImpl.java:371)
at org.hibernate.query.sqm.internal.SqmSelectionQueryImpl.doList(SqmSelectionQueryImpl.java:298)
at org.hibernate.query.spi.AbstractSelectionQuery.list(AbstractSelectionQuery.java:136)
at org.hibernate.query.SelectionQuery.getResultList(SelectionQuery.java:124)
at io.quarkus.hibernate.orm.panache.common.runtime.CommonPanacheQueryImpl.list(CommonPanacheQueryImpl.java:303)
at io.quarkus.hibernate.orm.panache.runtime.PanacheQueryImpl.list(PanacheQueryImpl.java:150)
at xx.persistence.repository.route.RouteRepository.getConsigneesForConsignor(RouteRepository.kt:111)
at xx.persistence.repository.route.RouteRepository_Subclass.getConsigneesForConsignor$$superforward(Unknown Source)
at xx.persistence.repository.route.RouteRepository_Subclass$$function$$26.apply(Unknown Source)
at io.quarkus.arc.impl.AroundInvokeInvocationContext.proceed(AroundInvokeInvocationContext.java:73)
at io.quarkus.arc.impl.AroundInvokeInvocationContext.proceed(AroundInvokeInvocationContext.java:62)
at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorBase.invokeInOurTx(TransactionalInterceptorBase.java:136)
at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorBase.invokeInOurTx(TransactionalInterceptorBase.java:107)
at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorRequired.doIntercept(TransactionalInterceptorRequired.java:38)
at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorBase.intercept(TransactionalInterceptorBase.java:61)
at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorRequired.intercept(TransactionalInterceptorRequired.java:32)
at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorRequired_Bean.intercept(Unknown Source)
at io.quarkus.arc.impl.InterceptorInvocation.invoke(InterceptorInvocation.java:42)
at io.quarkus.arc.impl.AroundInvokeInvocationContext.perform(AroundInvokeInvocationContext.java:30)
at io.quarkus.arc.impl.InvocationContexts.performAroundInvoke(InvocationContexts.java:27)
at xx.persistence.repository.route.RouteRepository_Subclass.getConsigneesForConsignor(Unknown Source)
at xx.persistence.repository.route.RouteRepository_ClientProxy.getConsigneesForConsignor(Unknown Source)
at xx.repository.route.RouteRepositoryIntegrationTest.should return a list of active consignees for the given consignor when one matching consignor(RouteRepositoryIntegrationTest.kt:182)
at java.base/java.lang.reflect.Method.invoke(Method.java:578)
at io.quarkus.test.junit.QuarkusTestExtension.runExtensionMethod(QuarkusTestExtension.java:973)
at io.quarkus.test.junit.QuarkusTestExtension.interceptTestMethod(QuarkusTestExtension.java:823)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
Caused by: java.lang.NoSuchMethodException: xx.domain.BusinessUnitDetails.<init>(java.lang.String,xx.BusinessUnitType,java.lang.Integer)
at java.base/java.lang.Class.getConstructor0(Class.java:3641)
at java.base/java.lang.Class.getDeclaredConstructor(Class.java:2810)
at org.hibernate.sql.results.internal.RowTransformerConstructorImpl.<init>(RowTransformerConstructorImpl.java:37)
... 34 more
存储库层,脚本:
fun getSender(senderId: Long): UnitDetails {
return find(
"SELECT ud.code, ud.type, route.sequence " +
"FROM RouteEntity route " +
"JOIN UnitDetailsEntity ud ON ud.id = route.senderUnitDetailsId "
).project(UnitDetails::class.java).list()
}
我使用自定义构造函数来投影以满足休眠状态的聚合域对象:
class UnitDetails(
val businessUnit: BusinessUnit,
val sequence: Int
) {
constructor(
code: String,
type: BusinessUnitType,
sequence: Int
) : this(BusinessUnit(code, type), sequence)
}