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

能否通过Java Hibernate执行UNION查询合并两张数据表数据?

在Hibernate中合并同结构两张表数据到DTO列表的解决方案

原方案不可行的原因

  • HQL的UNION要求查询返回的结果类型必须完全一致,但Table和Table2是两个独立的实体类,直接执行select a from Table a union select a from Table2 a会抛出类型不匹配异常
  • 代码错误地将查询结果当作Object[]处理:如果查询的是实体对象,返回的是实体实例列表而非数组,会触发类型转换错误
  • 循环中dto对象仅初始化一次,后续赋值会覆盖之前的内容,最终列表里的所有元素都指向同一个对象,数据完全重复

可行实现方案

方案一:HQL查询字段直接映射到DTO

直接查询两张表的字段,避免实体类型不匹配问题,同时修正DTO初始化逻辑:

  1. 调整HQL语句,指定要查询的字段
select a.name, a.phoneNumber from Table a union select b.name, b.phoneNumber from Table2 b
  1. 修正数据转换代码
public ArrayList<DTO> getUsers(){
    ArrayList<DTO> flist = new ArrayList<>();
    String query = "select a.name, a.phoneNumber from Table a union select b.name, b.phoneNumber from Table2 b";
    try{
        AppEntityManager appEntMgr = AppEntityManager.getAppEntityManager();
        appEntMgr.startTransaction();
        
        Query q = appEntMgr.createQuery(query);
        q.setFirstResult(0);
        q.setMaxResults(10);
        
        List<Object[]> list = q.getResultList();
        
        for (Object[] row : list) {
            DTO dto = new DTO(); // 每次循环新建DTO实例
            dto.setName((String)row[0]);
            dto.setPhoneNumber((String)row[1]);
            flist.add(dto);
        }
    }catch (Exception e) {
        log.error("Exception ::" + e);
    }
    return flist;
}

方案二:基于父类的多态查询

通过公共父类统一实体类型,支持HQL的UNION查询:

  1. 创建映射父类,提取两张表的公共字段
@MappedSuperclass
public abstract class BaseTable {
    @Id
    @Column(name="NAME")
    private String name;

    @Column(name="PHONE")
    private String phoneNumber;

    // 公共getter/setter
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public String getPhoneNumber() { return phoneNumber; }
    public void setPhoneNumber(String phoneNumber) { this.phoneNumber = phoneNumber; }
}
  1. 修改实体类继承父类
@Entity
@Table(name="TABLE")
public class Table extends BaseTable {
    // 无需重复定义字段,继承父类即可
}
@Entity
@Table(name="TABLE_2")
public class Table2 extends BaseTable {
    // 无需重复定义字段,继承父类即可
}
  1. 使用父类进行HQL查询并转换DTO
public ArrayList<DTO> getUsers(){
    ArrayList<DTO> flist = new ArrayList<>();
    String query = "select a from BaseTable a union select b from BaseTable b";
    try{
        AppEntityManager appEntMgr = AppEntityManager.getAppEntityManager();
        appEntMgr.startTransaction();
        
        Query q = appEntMgr.createQuery(query);
        q.setFirstResult(0);
        q.setMaxResults(10);
        
        List<BaseTable> list = q.getResultList();
        
        for (BaseTable entity : list) {
            DTO dto = new DTO();
            dto.setName(entity.getName());
            dto.setPhoneNumber(entity.getPhoneNumber());
            flist.add(dto);
        }
    }catch (Exception e) {
        log.error("Exception ::" + e);
    }
    return flist;
}

方案三:原生SQL查询

如果HQL的限制较多,可直接使用原生SQL绕过实体类型限制:

public ArrayList<DTO> getUsers(){
    ArrayList<DTO> flist = new ArrayList<>();
    String sql = "SELECT NAME, PHONE FROM TABLE UNION SELECT NAME, PHONE FROM TABLE_2";
    try{
        AppEntityManager appEntMgr = AppEntityManager.getAppEntityManager();
        appEntMgr.startTransaction();
        
        Query q = appEntMgr.createNativeQuery(sql);
        q.setFirstResult(0);
        q.setMaxResults(10);
        
        List<Object[]> list = q.getResultList();
        
        for (Object[] row : list) {
            DTO dto = new DTO();
            dto.setName((String)row[0]);
            dto.setPhoneNumber((String)row[1]);
            flist.add(dto);
        }
    }catch (Exception e) {
        log.error("Exception ::" + e);
    }
    return flist;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 21:01:05