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

eqoofvh9  于 2023-05-29  发布在  Kotlin
关注(0)|答案(1)|浏览(208)

我在基于Hibernate的应用程序中执行HQL查询时遇到了ClassCastException。我收到的错误消息是:

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)

完整代码如下:(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**上执行更新查询时出错

bgibtngc

bgibtngc1#

问题解决了!我会尽量解释得更好

收到的错误消息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的不正确使用有关

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")
    }
  }

使用trycatch是在代码中处理异常的一种方法。在提供的代码片段中,try和catch用于捕获和处理在执行updateProgress()函数期间可能发生的任何异常。
总的来说,trycatch用于提供健壮性和错误处理能力,以确保程序可以从异常中正常恢复并继续执行。
希望这个能帮上忙

相关问题