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

如何使用CriteriaQuery预获取子对象中的treinamentosNecessarios集合?

问题:JPA CriteriaQuery预获取嵌套关联集合

我有两个实体类:

实体类 Funcionario

@Entity
@Table(name = "funcionarios")
public class Funcionario extends Model {
    
    ....
    
    @NotFound(action = NotFoundAction.IGNORE)
    @ManyToOne(fetch = FetchType.LAZY, optional = true)
    private Cargo cargo;
    ...
    
}

实体类 Cargo

@Entity
@Table(name = "cargos")
public class Cargo extends Model {
    
    @Column(nullable = false, unique = true, columnDefinition = "TEXT")
    private String cargo = "";
    
    
    @ManyToMany(fetch = FetchType.LAZY)
    private Set<Treinamento> treinamentosNecessarios;
    
}

我尝试加载Funcionario实体时,预获取其关联的Cargo以及Cargo中的treinamentosNecessarios集合。目前代码能获取到Cargo,但无法加载treinamentosNecessarios。请问如何通过CriteriaQuery实现从Cargo中预获取这个集合?

现有代码:

@Override
public Funcionario find(Long id, Session session, boolean closeSession) {
    try {
            
        CriteriaBuilder cb = session.getCriteriaBuilder();
    
        CriteriaQuery<Funcionario> criteriaQuery = cb.createQuery(Funcionario.class);
    
        Root<Funcionario> root = criteriaQuery.from(Funcionario.class);
        root.fetch("avaliacoes", JoinType.LEFT);
        root.fetch("treinamentosRealizados", JoinType.LEFT);
        root.fetch("cargo", JoinType.LEFT);
            //root.fetch("cargo.treinamentosNecessarios", JoinType.LEFT);
    
        criteriaQuery.select(root);
        criteriaQuery.where(cb.equal(root.get("id"), id));
    
        Query<Funcionario> query = session.createQuery(criteriaQuery);
    
        Funcionario singleResult = query.getSingleResult();
        return singleResult;
    
    } catch (Exception ex) {
        throw ex;
    } finally {
        if (session != null && closeSession) {
            session.close();
        }
    }
}

解决方案

要预获取嵌套的treinamentosNecessarios集合,不能直接使用root.fetch("cargo.treinamentosNecessarios")这种点路径写法,需要先获取cargo对应的Fetch对象,再通过该对象继续预获取嵌套集合。修改后的代码如下:

@Override
public Funcionario find(Long id, Session session, boolean closeSession) {
    try {
            
        CriteriaBuilder cb = session.getCriteriaBuilder();
    
        CriteriaQuery<Funcionario> criteriaQuery = cb.createQuery(Funcionario.class);
    
        Root<Funcionario> root = criteriaQuery.from(Funcionario.class);
        root.fetch("avaliacoes", JoinType.LEFT);
        root.fetch("treinamentosRealizados", JoinType.LEFT);
        
        // 先获取cargo的Fetch对象
        Fetch<Funcionario, Cargo> cargoFetch = root.fetch("cargo", JoinType.LEFT);
        // 通过cargoFetch继续预获取treinamentosNecessarios集合
        cargoFetch.fetch("treinamentosNecessarios", JoinType.LEFT);
    
        criteriaQuery.select(root);
        criteriaQuery.where(cb.equal(root.get("id"), id));
    
        Query<Funcionario> query = session.createQuery(criteriaQuery);
    
        Funcionario singleResult = query.getSingleResult();
        return singleResult;
    
    } catch (Exception ex) {
        throw ex;
    } finally {
        if (session != null && closeSession) {
            session.close();
        }
    }
}

关键说明

  • 嵌套关联的预获取需要逐层处理:先获取一级关联的Fetch对象,再基于该对象调用fetch方法加载下一级关联,不能直接使用点分隔的路径字符串。
  • 这种写法会生成包含多层左连接的SQL语句,一次性加载Funcionario、Cargo和treinamentosNecessarios的所有数据,避免懒加载触发的N+1查询问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 05:31:17