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

Hibernate Transformers.aliasToBean填充双主键字段问题求助

解决Hibernate 3.2.4中用Transformers.aliasToBean映射带复合主键的Tbcompany问题

你遇到的核心问题是:Hibernate 3.2.4的Transformers.aliasToBean只支持平级属性的映射,而你的Tbcompany类里包含一个复合主键对象TbcompanyId,直接用默认转换器无法自动填充这个嵌套对象里的主键字段。下面给你两种实用的解决方案:

方案一:自定义ResultTransformer(推荐)

自己实现一个结果转换器,手动处理复合主键的字段映射,能直接把查询结果转换为Tbcompany实体。

步骤1:先明确TbcompanyId的结构(如果和你的实际代码不符,调整字段名即可)

public class TbcompanyId implements Serializable {
    private String companyCode; // 第一个主键字段
    private String branchCode;  // 第二个主键字段

    // 必须实现getter/setter、equals()和hashCode()方法
    // Hibernate要求复合主键类必须实现Serializable
    public String getCompanyCode() { return companyCode; }
    public void setCompanyCode(String companyCode) { this.companyCode = companyCode; }
    public String getBranchCode() { return branchCode; }
    public void setBranchCode(String branchCode) { this.branchCode = branchCode; }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        TbcompanyId that = (TbcompanyId) o;
        return companyCode.equals(that.companyCode) && branchCode.equals(that.branchCode);
    }

    @Override
    public int hashCode() {
        return 31 * companyCode.hashCode() + branchCode.hashCode();
    }
}

步骤2:实现自定义ResultTransformer

import org.hibernate.transform.ResultTransformer;
import java.util.List;

public class TbcompanyResultTransformer implements ResultTransformer {

    @Override
    public Object transformTuple(Object[] tuple, String[] aliases) {
        Tbcompany company = new Tbcompany();
        TbcompanyId id = new TbcompanyId();

        // 遍历查询结果的别名和对应值,分别填充主键对象和实体属性
        for (int i = 0; i < aliases.length; i++) {
            String alias = aliases[i];
            Object value = tuple[i];

            if ("id.companyCode".equals(alias)) {
                id.setCompanyCode((String) value);
            } else if ("id.branchCode".equals(alias)) {
                id.setBranchCode((String) value);
            } else if ("hcompanycode".equals(alias)) {
                company.setHcompanycode((String) value);
            }
            // 其他字段可以在这里补充
        }

        company.setId(id);
        return company;
    }

    @Override
    public List transformList(List collection) {
        // 直接返回处理后的集合,不需要额外修改
        return collection;
    }
}

步骤3:在查询中使用自定义转换器

用SQLQuery查询的情况:

String sql = "SELECT " +
             "c.company_code AS `id.companyCode`, " +
             "c.branch_code AS `id.branchCode`, " +
             "c.hcompanycode " +
             "FROM tbcompany c";

SQLQuery query = session.createSQLQuery(sql);
query.setResultTransformer(new TbcompanyResultTransformer());
List<Tbcompany> companyList = query.list();

用Criteria查询的情况:

Criteria criteria = session.createCriteria(Tbcompany.class);
criteria.setProjection(Projections.projectionList()
        .add(Projections.property("id.companyCode"), "id.companyCode")
        .add(Projections.property("id.branchCode"), "id.branchCode")
        .add(Projections.property("hcompanycode"), "hcompanycode"));

criteria.setResultTransformer(new TbcompanyResultTransformer());
List<Tbcompany> companyList = criteria.list();

方案二:先映射到平级DTO再转换为实体

如果不想自定义转换器,可以先把查询结果映射到一个没有嵌套对象的DTO,再手动转换为Tbcompany实体。

步骤1:创建平级DTO

public class TbcompanyDTO {
    private String companyCode;
    private String branchCode;
    private String hcompanycode;

    // getter和setter方法
    public String getCompanyCode() { return companyCode; }
    public void setCompanyCode(String companyCode) { this.companyCode = companyCode; }
    public String getBranchCode() { return branchCode; }
    public void setBranchCode(String branchCode) { this.branchCode = branchCode; }
    public String getHcompanycode() { return hcompanycode; }
    public void setHcompanycode(String hcompanycode) { this.hcompanycode = hcompanycode; }
}

步骤2:查询并转换

// 用SQLQuery查询并映射到DTO
String sql = "SELECT " +
             "c.company_code AS companyCode, " +
             "c.branch_code AS branchCode, " +
             "c.hcompanycode " +
             "FROM tbcompany c";

SQLQuery query = session.createSQLQuery(sql);
query.setResultTransformer(Transformers.aliasToBean(TbcompanyDTO.class));
List<TbcompanyDTO> dtoList = query.list();

// 手动转换为Tbcompany实体
List<Tbcompany> companyList = new ArrayList<>();
for (TbcompanyDTO dto : dtoList) {
    Tbcompany company = new Tbcompany();
    TbcompanyId id = new TbcompanyId();
    id.setCompanyCode(dto.getCompanyCode());
    id.setBranchCode(dto.getBranchCode());
    company.setId(id);
    company.setHcompanycode(dto.getHcompanycode());
    companyList.add(company);
}

注意事项

  • 复合主键类TbcompanyId必须实现Serializable,并且正确重写equals()和hashCode()方法,这是Hibernate处理复合主键的硬性要求。
  • Hibernate 3.2.4版本比较老旧,如果后续有升级计划,新版本的Hibernate(比如5.x+)支持更灵活的结果映射方式,但当前版本只能用上面的两种方法解决。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:02:54