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

Hibernate 6原生查询实现类似Join Fetch关联实体加载问题

Hibernate 6原生查询加载关联实体时重复别名异常的解决办法

问题背景

在Hibernate 5中,执行以下原生查询可同时获取Instrument及其关联的Exchange实体:

@Query(nativeQuery = true, value = """
select i.*, e.* from instrument i
   join exchange e on e.id = i.exchange_id
""")
List<Instrument> findAllInstrumentsHibernate5();

迁移至Hibernate 6后,执行相同查询抛出异常:

org.springframework.orm.jpa.JpaSystemException: Encountered a duplicated sql alias [id] during auto-discovery of a native-sql query

核心原因是Hibernate 6调整了原生查询的结果映射逻辑,不仅会检测重复列别名(两个实体均含id列),且默认不再按列名匹配映射。尝试指定具体列后仍无法加载关联Exchange,以下是无需切换JPQL的解决办法。

实体类定义:

@Entity
public class Instrument {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "native")
    @GenericGenerator(name = "native")
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "EXCHANGE_ID", referencedColumnName = "ID",
        foreignKey = @ForeignKey(name = "fk__instrument__exchange_id__exchange"))
    private Exchange exchange;
}

@Entity
public class Exchange {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "native")
    @GenericGenerator(name = "native")
    private Long id;

    private String name;
}

解决办法

1. 自定义结果集映射(@SqlResultSetMapping)

为重复列指定唯一别名,通过@SqlResultSetMapping明确实体与列的映射关系,彻底避免别名冲突。

首先在Instrument实体上添加映射定义:

@Entity
@SqlResultSetMapping(
    name = "InstrumentWithExchangeMapping",
    entities = {
        @EntityResult(
            entityClass = Instrument.class,
            fields = {
                @FieldResult(name = "id", column = "i_id"),
                @FieldResult(name = "exchange", column = "exchange_id")
            }
        ),
        @EntityResult(
            entityClass = Exchange.class,
            fields = {
                @FieldResult(name = "id", column = "e_id"),
                @FieldResult(name = "name", column = "e_name")
            }
        )
    }
)
public class Instrument {
    // 原有实体代码
}

修改原生查询,指定列别名并引用映射:

@Query(nativeQuery = true, value = """
select i.id as i_id, i.exchange_id,
       e.id as e_id, e.name as e_name
from instrument i
join exchange e on e.id = i.exchange_id
""", resultSetMapping = "InstrumentWithExchangeMapping")
List<Instrument> findAllInstrumentsHibernate6();

2. 结合抓取配置文件(@FetchProfile)

定义抓取配置强制加载关联实体,同时为查询列指定不冲突的别名。

在Instrument实体上添加抓取配置:

@Entity
@FetchProfile(
    name = "instrument-with-exchange",
    fetchOverrides = {
        @FetchProfile.FetchOverride(
            entity = Instrument.class,
            association = "exchange",
            mode = FetchMode.JOIN
        )
    }
)
public class Instrument {
    // 原有实体代码
}

修改查询并激活抓取配置:

@Query(nativeQuery = true, value = """
select i.*, e.id as exchange_id, e.name as exchange_name
from instrument i
join exchange e on e.id = i.exchange_id
""")
@FetchProfile(name = "instrument-with-exchange")
List<Instrument> findAllInstrumentsHibernate6();

3. 自定义结果转换器(ResultTransformer)

实现Hibernate的ResultTransformer接口,手动控制JDBC结果集到实体的映射逻辑,完全规避别名问题。

创建转换器类:

public class InstrumentExchangeTransformer implements ResultTransformer {

    @Override
    public Object transformTuple(Object[] tuple, String[] aliases) {
        Instrument instrument = new Instrument();
        instrument.setId((Long) tuple[0]);
        
        Exchange exchange = new Exchange();
        exchange.setId((Long) tuple[1]);
        exchange.setName((String) tuple[2]);
        
        instrument.setExchange(exchange);
        return instrument;
    }

    @Override
    public List transformList(List collection) {
        return collection;
    }
}

在查询中使用转换器(需通过EntityManager获取Hibernate Query对象):

// 在Repository实现类中编写
public List<Instrument> findAllInstrumentsHibernate6() {
    String sql = """
        select i.id, e.id, e.name
        from instrument i
        join exchange e on e.id = i.exchange_id
        """;
    return entityManager.createNativeQuery(sql)
        .unwrap(org.hibernate.query.Query.class)
        .setResultTransformer(new InstrumentExchangeTransformer())
        .getResultList();
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 01:05:07