如何在执行HQL查询时修复Hibernate中的ClassCastException?

huangapple go评论66阅读模式
英文:

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.FromReferenceNodeorg.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 &#39;app&#39;)
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.&lt;init&gt;(HQLQueryPlan.java:113)
at org.hibernate.engine.query.spi.HQLQueryPlan.&lt;init&gt;(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 = &quot;daily_quests&quot;,
indexes = [
Index(name = &quot;idx_daily_quests_user&quot;, columnList = &quot;user_id&quot;)
]
)
abstract class ServerDailyQuest(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Int,
@ManyToOne
val user: User,
@Column(nullable = false, name = &quot;questIndex&quot;) 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 = &quot;id.quest&quot;)
val rewards: MutableList&lt;ServerDailyQuestReward&gt;
) {
@get:Transient
abstract val description: LocalizedString
suspend fun updateProgress() {
HibernateUtils.createEntityManager().let { entityManager -&gt;
entityManager.transaction.begin()
withContext(Dispatchers.IO) {
val queryString = &quot;UPDATE ServerDailyQuest SET current = :current, new = :new, completed = :completed WHERE id = :id&quot;
entityManager
.createQuery(queryString)
.setParameter(&quot;current&quot;, current)
.setParameter(&quot;id&quot;, id)
.setParameter(&quot;new&quot;, new)
.setParameter(&quot;completed&quot;, completed)
.executeUpdate()
}
entityManager.transaction.commit()
entityManager.close()
}
}
}

The error occurs when I try to execute an update query using the following code:

val queryString = &quot;UPDATE ServerDailyQuest SET current = :current, new = :new, completed = :completed WHERE id = :id&quot;

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的不正确使用有关。

在代码中使用 trycatch 是一种处理异常的方式。在提供的代码片段中,使用 try 和 catch 来捕获并处理在执行 updateProgress() 函数期间可能发生的任何异常。

总的来说,trycatch 用于提供强大的错误处理能力,以确保程序可以优雅地从异常中恢复,并继续执行。

希望这能帮助。

英文:

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 = &quot;UPDATE ServerDailyQuest SET current = :current, new = :new, completed = :completed WHERE id = :id&quot;
withContext(Dispatchers.IO) {
val query = entityManager.createQuery(queryString)
.setParameter(&quot;current&quot;, current)
.setParameter(&quot;new&quot;, new)
.setParameter(&quot;completed&quot;, completed)
.setParameter(&quot;id&quot;, id)
val rowCount = query.executeUpdate()
println(&quot;Rows updated: $rowCount&quot;)
}
entityManager.transaction.commit()
entityManager.close()
} catch (ex: Exception) {
println(&quot;Error occurred while updating progress: $ex&quot;)
}
}

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

huangapple
  • 本文由 发表于 2023年5月28日 03:10:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/76348592.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定