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

Hibernate 6 NativeQuery查询同类型多实体仅返回首个实体问题

Hibernate 6 NativeQuery 查询同类型多实体重复返回首个实体的解决方法

问题现象

从Hibernate 5迁移至Hibernate 6后,使用NativeQuery查询同类型的多个实体时,返回结果中所有实体均与首个实体重复。例如执行以下代码:

List<Object[]> res = sess.createSQLQuery("SELECT {cat.*}, {m.*}  FROM CATS c, CATS m WHERE c.MOTHER_ID = m.ID")
 .addEntity("cat", Cat.class)
 .addEntity("mother", Cat.class)
 .list();

Hibernate 5中会返回两个不同的Cat实体(子猫和母猫),但Hibernate 6中返回的是两个完全相同的子猫实体。同时Hibernate 6官方文档已移除同类型多实体查询的示例,替换为不同实体类型的查询示例。

原因分析

Hibernate 6对NativeQuery的实体解析逻辑进行了调整:当查询同类型的多个实体时,默认会复用第一个实体的映射规则,导致后续同类型实体无法被正确解析为独立对象。

解决方案

方案1:使用@SqlResultSetMapping显式定义结果映射

通过注解定义明确的结果集映射,区分同类型的不同实体:

@SqlResultSetMapping(
    name = "CatAndMotherMapping",
    entities = {
        @EntityResult(entityClass = Cat.class, name = "cat"),
        @EntityResult(entityClass = Cat.class, name = "mother")
    }
)

查询时指定该映射:

List<Object[]> res = sess.createNativeQuery(
    "SELECT {cat.*}, {mother.*} FROM CATS cat, CATS mother WHERE cat.MOTHER_ID = mother.ID",
    "CatAndMotherMapping"
).list();

方案2:使用Tuple接收结果并通过别名获取实体

通过Tuple类型接收结果,然后根据表别名获取对应的实体对象:

List<Tuple> tuples = sess.createNativeQuery(
    "SELECT c.*, m.* FROM CATS c, CATS m WHERE c.MOTHER_ID = m.ID",
    Tuple.class
)
.addEntity("c", Cat.class)
.addEntity("m", Cat.class)
.list();

// 遍历处理结果
for (Tuple tuple : tuples) {
    Cat cat = (Cat) tuple.get("c");
    Cat mother = (Cat) tuple.get("m");
    // 业务逻辑处理
}

方案3:显式指定列别名与实体的映射

修改SQL语句,为每个表的列添加专属别名,确保Hibernate能区分不同实体的字段:

List<Object[]> res = sess.createSQLQuery(
    "SELECT c.id AS cat_id, c.name AS cat_name, m.id AS mother_id, m.name AS mother_name " +
    "FROM CATS c, CATS m WHERE c.MOTHER_ID = m.ID"
)
.addEntity("cat", Cat.class)
.addEntity("mother", Cat.class)
.list();

这种方式适合字段较少的场景,字段较多时建议使用前两种方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 09:00:09