You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从Hibernate 5.x迁移到6.2后JPQL实例化查询报错求助

Hibernate 5.x迁移到6.2后的动态实例化报错问题

问题场景

将项目从Hibernate 5.x迁移到6.2后,原本正常运行的JPQL查询出现实例化错误,以下是相关代码与报错信息:

原始查询代码

public List<MarketCommodityInfo> getMarketCommodityInfoForCommodities(Double longitude, Double latitude,
            Integer page) {

        return getEntityManager().createQuery(
                "SELECT new org.kisanag.model.mandi.MarketCommodityInfo (mci, earth_distance(ll_to_earth(m.latitude, m.longitude), ll_to_earth(:latitude, :longitude)) / :conversion AS distance) FROM MarketCommodityInfo mci JOIN mci.id.market m JOIN mci.id.commodity c WHERE earth_distance(ll_to_earth(m.latitude, m.longitude),ll_to_earth(:latitude, :longitude)) < :within * :conversion ORDER BY distance, mci.id.arrivalDate, c.name",
                MarketCommodityInfo.class)
                .setParameter("latitude", latitude)
                .setParameter("longitude", longitude)
                .setParameter("within", 200)
                .setParameter("conversion", 1000)
                .setMaxResults(pageSize)
                .setFirstResult(page * pageSize)
                .getResultList();

    }

第一次报错信息

Caused by: java.lang.IllegalStateException: Could not determine appropriate instantiation strategy - no matching constructor found and one or more arguments did not define alias for bean-injection
        at org.hibernate.sql.results.graph.instantiation.internal.DynamicInstantiationResultImpl.resolveAssembler(DynamicInstantiationResultImpl.java:197)
        at org.hibernate.sql.results.graph.instantiation.internal.DynamicInstantiationResultImpl.createResultAssembler(DynamicInstantiationResultImpl.java:106)
        at org.hibernate.sql.results.jdbc.internal.StandardJdbcValuesMapping.resolveAssemblers(StandardJdbcValuesMapping.java:53)
        at org.hibernate.sql.results.internal.ResultsHelper.createRowReader(ResultsHelper.java:78)
        at org.hibernate.sql.results.internal.ResultsHelper.createRowReader(ResultsHelper.java:64)
        at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.doExecuteQuery(JdbcSelectExecutorStandardImpl.java:341)
        at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.executeQuery(JdbcSelectExecutorStandardImpl.java:168)
        at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.list(JdbcSelectExecutorStandardImpl.java:93)
        at org.hibernate.sql.exec.spi.JdbcSelectExecutor.list(JdbcSelectExecutor.java:31)
        at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.lambda$new$0(ConcreteSqmSelectQueryPlan.java:109)
        at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.withCacheableSqmInterpretation(ConcreteSqmSelectQueryPlan.java:302)
        at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.performList(ConcreteSqmSelectQueryPlan.java:243)
        at org.hibernate.query.sqm.internal.QuerySqmImpl.doList(QuerySqmImpl.java:521)
        at org.hibernate.query.spi.AbstractSelectionQuery.list(AbstractSelectionQuery.java:367)
        at org.hibernate.query.sqm.internal.QuerySqmImpl.list(QuerySqmImpl.java:1084)
        at org.hibernate.query.Query.getResultList(Query.java:119)

修改后的查询(添加别名)

SELECT new org.kisanag.model.mandi.MarketCommodityInfo (mci AS *commodityInfo*, earth_distance(ll_to_earth(m.latitude, m.longitude), ll_to_earth(:latitude, :longitude)) / :conversion AS distance) FROM MarketCommodityInfo mci JOIN mci.id.market m JOIN mci.id.commodity c WHERE earth_distance(ll_to_earth(m.latitude, m.longitude),ll_to_earth(:latitude, :longitude)) < :within * :conversion ORDER BY distance, mci.id.arrivalDate, c.name

第二次报错信息

Caused by: org.hibernate.query.sqm.sql.internal.InstantiationException: Unable to determine dynamic instantiation injection strategy for org.kisanag.model.mandi.MarketCommodityInfo#commodityInfo
        at org.hibernate.sql.results.graph.instantiation.internal.DynamicInstantiationAssemblerInjectionImpl.lambda$new$0(DynamicInstantiationAssemblerInjectionImpl.java:82)
        at org.hibernate.internal.util.beans.BeanInfoHelper.visitBeanInfo(BeanInfoHelper.java:55)
        at org.hibernate.internal.util.beans.BeanInfoHelper.visitBeanInfo(BeanInfoHelper.java:48)
        at org.hibernate.sql.results.graph.instantiation.internal.DynamicInstantiationAssemblerInjectionImpl.<init>(DynamicInstantiationAssemblerInjectionImpl.java:35)
        at org.hibernate.sql.results.graph.instantiation.internal.DynamicInstantiationResultImpl.resolveAssembler(DynamicInstantiationResultImpl.java:208)
        at org.hibernate.sql.results.graph.instantiation.internal.DynamicInstantiationResultImpl.createResultAssembler(DynamicInstantiationResultImpl.java:106)
        at org.hibernate.sql.results.jdbc.internal.StandardJdbcValuesMapping.resolveAssemblers(StandardJdbcValuesMapping.java:53)
        at org.hibernate.sql.results.internal.ResultsHelper.createRowReader(ResultsHelper.java:78)
        at org.hibernate.sql.results.internal.ResultsHelper.createRowReader(ResultsHelper.java:64)
        at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.doExecuteQuery(JdbcSelectExecutorStandardImpl.java:341)
        at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.executeQuery(JdbcSelectExecutorStandardImpl.java:168)
        at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.list(JdbcSelectExecutorStandardImpl.java:93)
        at org.hibernate.sql.exec.spi.JdbcSelectExecutor.list(JdbcSelectExecutor.java:31)
        at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.lambda$new$0(ConcreteSqmSelectQueryPlan.java:109)
        at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.withCacheableSqmInterpretation(ConcreteSqmSelectQueryPlan.java:302)
        at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.performList(ConcreteSqmSelectQueryPlan.java:243)
        at org.hibernate.query.sqm.internal.QuerySqmImpl.doList(QuerySqmImpl.java:521)
        at org.hibernate.query.spi.AbstractSelectionQuery.list(AbstractSelectionQuery.java:367)
        at org.hibernate.query.sqm.internal.QuerySqmImpl.list(QuerySqmImpl.java:1084)
        at org.hibernate.query.Query.getResultList(Query.java:119)

实体类代码

import jakarta.persistence.EmbeddedId;
import jakarta.persistence.Entity;
import jakarta.persistence.Transient;

@Entity
public class MarketCommodityInfo {

    @EmbeddedId
    public MarketCommodityInfoKey id;

    public Double minPrice;
    public Double modalPrice;
    public Double maxPrice;
    public String unit;

    @Transient
    public Double distance;

    public MarketCommodityInfo() {
    }

    public MarketCommodityInfo(MarketCommodityInfo commodityInfo, Double distance) {
        this.id = commodityInfo.id;
        this.minPrice = commodityInfo.minPrice;
        this.modalPrice = commodityInfo.modalPrice;
        this.maxPrice = commodityInfo.maxPrice;
        this.unit = commodityInfo.unit;
        this.distance = distance;
    }
}

嵌入式主键类代码

import java.io.Serializable;
import java.util.Date;

import jakarta.persistence.Embeddable;
import jakarta.persistence.OneToOne;

@Embeddable
public class MarketCommodityInfoKey implements Serializable {

    public Date arrivalDate;

    @OneToOne
    public Commodity commodity;

    @OneToOne
    public Market market;

    public MarketCommodityInfoKey() {
    }

    public MarketCommodityInfoKey(Date arrivalDate, Commodity commodity, Market market) {
        this.arrivalDate = arrivalDate;
        this.commodity = commodity;
        this.market = market;
    }

    @Override
    public String toString() {
        return "MarketCommodityInfoKey [arrivalDate=" + arrivalDate + ", commodity=" + commodity + ", market="
                + market + "]";
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((arrivalDate == null) ? 0 : arrivalDate.hashCode());
        result = prime * result + ((commodity == null) ? 0 : commodity.hashCode());
        result = prime * result + ((market == null) ? 0 : market.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        MarketCommodityInfoKey other = (MarketCommodityInfoKey) obj;
        if (arrivalDate == null) {
            if (other.arrivalDate != null)
                return false;
        } else if (!arrivalDate.equals(other.arrivalDate))
            return false;
        if (commodity == null) {
            if (other.commodity != null)
                return false;
        } else if (!commodity.equals(other.commodity))
            return false;
        if (market == null) {
            if (other.market != null)
                return false;
        } else if (!market.equals(other.market))
            return false;
        return true;
    }

}

解决方案

错误原因

Hibernate 6.x对JPQL动态实例化的语法检查更严格,核心问题出在构造函数参数的写法上:

  1. 原始查询中,在new的参数里给distance加了AS distance,导致Hibernate无法匹配到实体类中MarketCommodityInfo(MarketCommodityInfo, Double)的构造函数,进而尝试使用bean注入策略,但不符合注入条件,触发第一次报错。
  2. 第二次修改时添加的mci AS *commodityInfo*完全错误,实体类中不存在名为commodityInfo的属性,Hibernate尝试bean注入时找不到对应字段,触发第二次报错。

修正后的查询

去掉构造函数参数中的所有别名,同时为了在ORDER BY中使用distance,可选择以下两种方案:

方案1:重复distance计算表达式

public List<MarketCommodityInfo> getMarketCommodityInfoForCommodities(Double longitude, Double latitude,
            Integer page) {

        String jpql = "SELECT new org.kisanag.model.mandi.MarketCommodityInfo (mci, earth_distance(ll_to_earth(m.latitude, m.longitude), ll_to_earth(:latitude, :longitude)) / :conversion) "
                + "FROM MarketCommodityInfo mci "
                + "JOIN mci.id.market m "
                + "JOIN mci.id.commodity c "
                + "WHERE earth_distance(ll_to_earth(m.latitude, m.longitude),ll_to_earth(:latitude, :longitude)) < :within * :conversion "
                + "ORDER BY earth_distance(ll_to_earth(m.latitude, m.longitude), ll_to_earth(:latitude, :longitude)) / :conversion, mci.id.arrivalDate, c.name";

        return getEntityManager().createQuery(jpql, MarketCommodityInfo.class)
                .setParameter("latitude", latitude)
                .setParameter("longitude", longitude)
                .setParameter("within", 200)
                .setParameter("conversion", 1000)
                .setMaxResults(pageSize)
                .setFirstResult(page * pageSize)
                .getResultList();

    }

方案2:使用子查询封装distance

如果不想重复计算表达式,可用子查询先封装distance字段:

public List<MarketCommodityInfo> getMarketCommodityInfoForCommodities(Double longitude, Double latitude,
            Integer page) {

        String jpql = "SELECT new org.kisanag.model.mandi.MarketCommodityInfo (mc.mci, mc.distance) "
                + "FROM (SELECT mci, earth_distance(ll_to_earth(m.latitude, m.longitude), ll_to_earth(:latitude, :longitude)) / :conversion AS distance "
                + "      FROM MarketCommodityInfo mci "
                + "      JOIN mci.id.market m "
                + "      JOIN mci.id.commodity c "
                + "      WHERE earth_distance(ll_to_earth(m.latitude, m.longitude),ll_to_earth(:latitude, :longitude)) < :within * :conversion) mc "
                + "ORDER BY mc.distance, mc.mci.id.arrivalDate, mc.mci.id.commodity.name";

        return getEntityManager().createQuery(jpql, MarketCommodityInfo.class)
                .setParameter("latitude", latitude)
                .setParameter("longitude", longitude)
                .setParameter("within", 200)
                .setParameter("conversion", 1000)
                .setMaxResults(pageSize)
                .setFirstResult(page * pageSize)
                .getResultList();

    }

两种方案都能正确匹配实体类的构造函数,解决实例化报错问题。


内容的提问来源于stack exchange,提问作者Mahen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 22:58:07