英文:
How can I fix a ClassCastException in Hibernate when executing an HQL query?
问题
在我的基于Hibernate的应用程序中执行HQL查询时,我遇到了ClassCastException错误。我收到的错误消息如下:
java.lang.ClassCastException: class org.hibernate.hql.internal.ast.tree.SqlNode无法转换为class org.hibernate.hql.internal.ast.tree.FromReferenceNode(org.hibernate.hql.internal.ast.tree.SqlNode和org.hibernate.hql.internal.ast.tree.FromReferenceNode位于'应用'加载器的未命名模块中)
at org.hibernate.hql.internal.ast.HqlSqlWalker.generateSyntheticDotNodeForNonQualifiedPropertyRef(HqlSqlWalker.java:747)
at org.hibernate.hql.internal.ast.HqlSqlWalker.lookupNonQualifiedProperty(HqlSqlWalker.java:740)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.propertyRef(HqlSqlBaseWalker.java:1181)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.assignment(HqlSqlBaseWalker.java:1066)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.setClause(HqlSqlBaseWalker.java:782)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.updateStatement(HqlSqlBaseWalker.java:398)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:286)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:276)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:192)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:144)
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:113)
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:73)
at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:162)
at org.hibernate.internal.AbstractSharedSessionContract.getQueryPlan(AbstractSharedSessionContract.java:622)
at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:734)
at org.hibernate.internal.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:23)
at jp.assasans.protanki.server.quests.ServerDailyQuest$updateProgress$2$1.invokeSuspend(ServerDailyQuest.kt:48)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.kt:42)
at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:95)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:749)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)
以下是完整的Kotlin代码:
package server.quests
import jakarta.persistence.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import server.HibernateUtils
import server.client.User
import server.extensions.singleOrNullOrThrow
import server.utils.LocalizedString
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Table(
name = "daily_quests",
indexes = [
Index(name = "idx_daily_quests_user", columnList = "user_id")
]
)
abstract class ServerDailyQuest(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Int,
@ManyToOne
val user: User,
@Column(nullable = false, name = "questIndex") val index: Int, // INDEX is a reserved word in MariaDB
@Column(nullable = false) var current: Int,
@Column(nullable = false) var required: Int,
@Column(nullable = false) var new: Boolean,
@Column(nullable = false) var completed: Boolean,
@OneToMany(targetEntity = ServerDailyQuestReward::class, mappedBy = "id.quest")
val rewards: MutableList<ServerDailyQuestReward>
) {
@get:Transient
abstract val description: LocalizedString
suspend fun updateProgress() {
HibernateUtils.createEntityManager().let { entityManager ->
entityManager.transaction.begin()
withContext(Dispatchers.IO) {
val queryString = "UPDATE ServerDailyQuest SET current = :current, new = :new, completed = :completed WHERE id = :id"
entityManager
.createQuery(queryString)
.setParameter("current", current)
.setParameter("id", id)
.setParameter("new", new)
.setParameter("completed", completed)
.executeUpdate()
}
entityManager.transaction.commit()
entityManager.close()
}
}
}
当我尝试执行以下代码来执行更新查询时出现错误:
val queryString = "UPDATE ServerDailyQuest SET current = :current, new = :new, completed = :completed WHERE id = :id"
以及:
entityManager
.createQuery(queryString)
错误发生在我尝试在ServerDailyQuest
上执行更新查询时。
英文:
I'm encountering a ClassCastException when executing an HQL query in my Hibernate-based application. The error message I'm receiving is:
java.lang.ClassCastException: class org.hibernate.hql.internal.ast.tree.SqlNode cannot be cast to class org.hibernate.hql.internal.ast.tree.FromReferenceNode (org.hibernate.hql.internal.ast.tree.SqlNode and org.hibernate.hql.internal.ast.tree.FromReferenceNode are in unnamed module of loader 'app')
at org.hibernate.hql.internal.ast.HqlSqlWalker.generateSyntheticDotNodeForNonQualifiedPropertyRef(HqlSqlWalker.java:747)
at org.hibernate.hql.internal.ast.HqlSqlWalker.lookupNonQualifiedProperty(HqlSqlWalker.java:740)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.propertyRef(HqlSqlBaseWalker.java:1181)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.assignment(HqlSqlBaseWalker.java:1066)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.setClause(HqlSqlBaseWalker.java:782)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.updateStatement(HqlSqlBaseWalker.java:398)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:286)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:276)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:192)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:144)
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:113)
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:73)
at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:162)
at org.hibernate.internal.AbstractSharedSessionContract.getQueryPlan(AbstractSharedSessionContract.java:622)
at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:734)
at org.hibernate.internal.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:23)
at jp.assasans.protanki.server.quests.ServerDailyQuest$updateProgress$2$1.invokeSuspend(ServerDailyQuest.kt:48)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.kt:42)
at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:95)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:749)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)
Complete code bellow: (kotlin)
package server.quests
import jakarta.persistence.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import server.HibernateUtils
import server.client.User
import server.extensions.singleOrNullOrThrow
import server.utils.LocalizedString
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Table(
name = "daily_quests",
indexes = [
Index(name = "idx_daily_quests_user", columnList = "user_id")
]
)
abstract class ServerDailyQuest(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Int,
@ManyToOne
val user: User,
@Column(nullable = false, name = "questIndex") val index: Int, // INDEX is a reserved word in MariaDB
@Column(nullable = false) var current: Int,
@Column(nullable = false) var required: Int,
@Column(nullable = false) var new: Boolean,
@Column(nullable = false) var completed: Boolean,
@OneToMany(targetEntity = ServerDailyQuestReward::class, mappedBy = "id.quest")
val rewards: MutableList<ServerDailyQuestReward>
) {
@get:Transient
abstract val description: LocalizedString
suspend fun updateProgress() {
HibernateUtils.createEntityManager().let { entityManager ->
entityManager.transaction.begin()
withContext(Dispatchers.IO) {
val queryString = "UPDATE ServerDailyQuest SET current = :current, new = :new, completed = :completed WHERE id = :id"
entityManager
.createQuery(queryString)
.setParameter("current", current)
.setParameter("id", id)
.setParameter("new", new)
.setParameter("completed", completed)
.executeUpdate()
}
entityManager.transaction.commit()
entityManager.close()
}
}
}
The error occurs when I try to execute an update query using the following code:
val queryString = "UPDATE ServerDailyQuest SET current = :current, new = :new, completed = :completed WHERE id = :id"
And:
entityManager
.createQuery(queryString)
The error occurs when I try to execute an update query on the ServerDailyQuest
答案1
得分: 1
问题已解决!我将尝试更好地解释。
收到的错误消息 java.lang.ClassCastException
表明在代码中发生了类型转换问题。具体来说,似乎尝试将类型为 org.hibernate.hql.internal.ast.tree.SqlNode
的对象转换为 org.hibernate.hql.internal.ast.tree.FromReferenceNode
,但这两种类型是不兼容的,不能直接进行类型转换。
为了解决这个问题,我采取了以下步骤,而不是直接使用 entityManager.createQuery(queryString)
来执行查询:
创建了一个单独的查询对象,并将 entityManager.createQuery(queryString)
分配给它。
需要注意的是,像 ClassCastException
这样的异常会在期望的对象类型之间存在不匹配时发生。在这种情况下,createQuery()
方法返回了一个类型为 SqlNode 的对象,与预期的 FromReferenceNode
类型不兼容。这导致了类型转换错误。
通过创建一个单独的查询对象,并直接在其上设置参数,您可以解决类型转换问题,并成功执行更新查询。此外,您还添加了异常处理,以捕获在更新过程中可能发生的任何潜在错误。
我希望这个解释能帮助其他可能遇到类似问题的人理解问题,并在他们自己的代码中实施解决方案。
简而言之,这与entityManager
的不正确使用有关。
在代码中使用 try
和 catch
是一种处理异常的方式。在提供的代码片段中,使用 try 和 catch 来捕获并处理在执行 updateProgress()
函数期间可能发生的任何异常。
总的来说,try
和 catch
用于提供强大的错误处理能力,以确保程序可以优雅地从异常中恢复,并继续执行。
希望这能帮助。
英文:
Guys problem solved! I will try to explain better
The error message received, java.lang.ClassCastException
, indicates that there was a problem with casting types in code. Specifically, it seems that tried to convert an object of type org.hibernate.hql.internal.ast.tree.SqlNode
to org.hibernate.hql.internal.ast.tree.FromReferenceNode
, but these two types are incompatible and cannot be directly cast to each other.
To fix the issue, Instead of directly executing the query using entityManager.createQuery(queryString)
, i took the following steps:
Created a separate query object by assigning entityManager.createQuery(queryString)
to it.
It's important to be aware that exceptions like ClassCastException
occur when there is a mismatch between the expected types of objects. In this case, the createQuery()
method returned an object of type SqlNode, which was incompatible with the expected type of FromReferenceNode
. This caused the casting error.
By creating a separate query object and setting the parameters directly on it, you work around the casting issue and successfully execute the update query. Additionally, you added exception handling to catch any potential errors that may occur during the update process.
I hope this explanation helps others who may encounter a similar issue to understand the problem and implement the solution in their own code.
In short, it is linked to the incorrect use of the entityManager
suspend fun updateProgress() {
try {
val entityManager = HibernateUtils.createEntityManager()
entityManager.transaction.begin()
val queryString = "UPDATE ServerDailyQuest SET current = :current, new = :new, completed = :completed WHERE id = :id"
withContext(Dispatchers.IO) {
val query = entityManager.createQuery(queryString)
.setParameter("current", current)
.setParameter("new", new)
.setParameter("completed", completed)
.setParameter("id", id)
val rowCount = query.executeUpdate()
println("Rows updated: $rowCount")
}
entityManager.transaction.commit()
entityManager.close()
} catch (ex: Exception) {
println("Error occurred while updating progress: $ex")
}
}
Using try
and catch
is a way to handle exceptions in code. In the provided code snippet, try and catch are used to capture and handle any exceptions that may occur during the execution of the updateProgress()
function.
Overall, try
and catch
are used to provide robustness and error handling capabilities to ensure the program can gracefully recover from exceptions and continue its execution.
Hope this helps
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论