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

使用Jakarta Criteria关联表时遇SemanticException错误求助

问题:Jakarta Criteria表关联报错Attribute [com.amfpromotora.entity.EmprestimosTabelas#tabcodigo(BASIC)] is not joinable

执行Jakarta Criteria表关联操作时触发如下错误:

org.hibernate.query.SemanticException: Attribute [com.amfpromotora.entity.EmprestimosTabelas#tabcodigo(BASIC)] is not joinable

预期实现的SQL关联逻辑:

FROM emprestimos_tabelas t
    JOIN emprestimos_bancos b ON t.banccodigo = b.banccodigo
    JOIN emprestimos_comiss_agenciador c ON t.tabcodigo = c.tabcodigo
    JOIN emprestimos_comiss_correspondente cc ON c.tabcodigo = cc.tabcodigo AND c.parmin = cc.parmin

实体类代码:
EmprestimosTabelas.java

@Entity
@Table(name = "emprestimos_tabelas", schema = "public", catalog = "joinconsig")
@Data
public class EmprestimosTabelas {
    @Id
    @Column(name = "tabcodigo")
    private int tabcodigo;
    @ManyToOne
    @JoinColumn(name = "banccodigo")
    private EmprestimosBancos banccodigo;
    @Basic
    @Column(name = "tabnome")
    private String tabnome;
    
    ...
}

EmprestimosComissAgenciador.java

@Entity
@Table(name = "emprestimos_comiss_agenciador", schema = "public", catalog = "joinconsig")
@IdClass(EmprestimosComissAgenciadorPK.class)
@Data
public class EmprestimosComissAgenciador {
    @Id
    @ManyToOne
    @JoinColumn(name = "tabcodigo")
    private EmprestimosTabelas tabcodigo;
    @Id
    @Column(name = "parmin")
    private int parmin;
    ...
}

EmprestimosComissCorrespondente.java

@Entity
@Table(name = "emprestimos_comiss_correspondente", schema = "public", catalog = "joinconsig")
@IdClass(EmprestimosComissCorrespondentePK.class)
@Data
public class EmprestimosComissCorrespondente {
    @Id
    @Column(name = "tabcodigo")
    private int tabcodigo;
    @Id
    @Column(name = "parmin")
    private int parmin;
    ...
}

当前CriteriaBuilder代码:

CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<CommissionTable> query = cb.createQuery(CommissionTable.class);
Root<EmprestimosTabelas> root = query.from(EmprestimosTabelas.class);

List<Predicate> predicates = new ArrayList<>();
Join<EmprestimosTabelas, EmprestimosBancos> bancosJoin = root.join("banccodigo");
Join<EmprestimosComissAgenciador, EmprestimosTabelas> comissAgenciadorJoin = root.join("tabcodigo");
Join<EmprestimosComissAgenciador, EmprestimosComissCorrespondente> comissCorrespondenteJoin = comissAgenciadorJoin.join("tabcodigo");

解决方案

问题根源

  1. 错误的关联方向:你尝试从EmprestimosTabelas的tabcodigo(基础int类型字段)执行join,但该字段是实体主键,并非关联实体属性,无法直接用于关联操作。按照你的SQL逻辑,emprestimos_comiss_agenciador通过外键关联到emprestimos_tabelas,关联方向应为EmprestimosTabelas反向关联EmprestimosComissAgenciador。
  2. 缺失反向关联属性:EmprestimosTabelas中未定义与EmprestimosComissAgenciador的反向关联,导致Criteria无法识别合法的关联关系。
  3. EmprestimosComissCorrespondente关联缺失:该实体的tabcodigo和parmin是基础类型字段,未关联到对应实体,无法直接通过Criteria进行join。

修复步骤

1. 补充实体间的关联关系

  • 修改EmprestimosTabelas.java,添加与EmprestimosComissAgenciador的反向关联:
@Entity
@Table(name = "emprestimos_tabelas", schema = "public", catalog = "joinconsig")
@Data
public class EmprestimosTabelas {
    @Id
    @Column(name = "tabcodigo")
    private int tabcodigo;
    @ManyToOne
    @JoinColumn(name = "banccodigo")
    private EmprestimosBancos banccodigo;
    @Basic
    @Column(name = "tabnome")
    private String tabnome;
    
    // 新增反向关联,mappedBy对应EmprestimosComissAgenciador中的关联属性名
    @OneToMany(mappedBy = "tabcodigo")
    private List<EmprestimosComissAgenciador> comissAgenciadores;
    
    ...
}
  • 修改EmprestimosComissCorrespondente.java,将基础类型ID改为关联实体:
@Entity
@Table(name = "emprestimos_comiss_correspondente", schema = "public", catalog = "joinconsig")
@IdClass(EmprestimosComissCorrespondentePK.class)
@Data
public class EmprestimosComissCorrespondente {
    @Id
    @ManyToOne
    @JoinColumn(name = "tabcodigo")
    private EmprestimosTabelas tabcodigo;
    @Id
    @Column(name = "parmin")
    private int parmin;
    
    ...
}

2. 修正CriteriaBuilder关联代码

基于实体关联关系,调整join的方向和属性:

CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<CommissionTable> query = cb.createQuery(CommissionTable.class);
Root<EmprestimosTabelas> root = query.from(EmprestimosTabelas.class);

List<Predicate> predicates = new ArrayList<>();
// 关联bancos,此部分逻辑正确
Join<EmprestimosTabelas, EmprestimosBancos> bancosJoin = root.join("banccodigo");
// 通过新增的反向关联属性关联到comissAgenciador
Join<EmprestimosTabelas, EmprestimosComissAgenciador> comissAgenciadorJoin = root.join("comissAgenciadores");
// 关联comissCorrespondente,同时补充parmin相等条件
Join<EmprestimosComissAgenciador, EmprestimosComissCorrespondente> comissCorrespondenteJoin = 
    comissAgenciadorJoin.join("tabcodigo", JoinType.INNER);
predicates.add(cb.equal(comissAgenciadorJoin.get("parmin"), comissCorrespondenteJoin.get("parmin")));

// 将条件加入查询
query.where(predicates.toArray(new Predicate[0]));

关键说明

  • 当外键在目标表时,主表必须定义反向关联(@OneToMany),Criteria才能识别可用于join的关联属性。
  • 禁止直接使用基础类型的主键字段执行join,必须基于实体间通过@ManyToOne/@OneToMany等注解定义的关联属性构建关联。
  • 对于复合主键的关联,要么让实体关联属性覆盖所有主键字段,要么通过Predicate补充额外的相等条件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 13:56:14