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

使用CriteriaQuery与CriteriaBuilder构建动态WHERE子句未获预期结果

问题:CriteriaBuilder使用conjunction谓词生成的WHERE子句始终为1=1

我正在使用CriteriaQuery和CriteriaBuilder构建动态WHERE子句,依据用户选择的可选过滤条件生成查询。但使用conjunction谓词后,未能生成正确的WHERE子句,WHERE子句始终为1=1,导致返回所有记录。

我的代码如下:

// Create CriteriaBuilder
CriteriaBuilder builder = session.getCriteriaBuilder();
// Create CriteriaQuery
CriteriaQuery<Tarea> criteria = builder.createQuery(Tarea.class);
// Set root
Root<Tarea> root = criteria.from(Tarea.class);
criteria.select(root);
if(getSortColumn()!= null && !getSortColumn().equals("")) {
    criteria.orderBy(builder.asc(root.get(getSortColumn())));
}
Predicate predFinal = builder.conjunction();
if(filtro.getClasificacionTarea() != null && filtro.getClasificacionTarea().size()>0) {
    Predicate predClasificacion = builder.disjunction();
    for(Clasificacion clas : filtro.getClasificacionTarea()) {
        predClasificacion.getExpressions().add(builder.equal(root.get("clasificacion").get("id"), clas.getId()));
    }
    predFinal.getExpressions().add(predClasificacion);
}
if(filtro.getProyecto() != null) {
    Predicate predicateProyecto;
    predicateProyecto = builder.and(builder.equal(root.get("OT").get("proyecto"), filtro.getProyecto()));
    predFinal.getExpressions().add(predicateProyecto);
}
if(filtro.getCliente() != null) {
    Predicate predicateCliente;
    predicateCliente = builder.and(builder.equal(root.get("ot").get("cliente").get("id"), filtro.getCliente().getId()));
    predFinal.getExpressions().add(predicateCliente);
}
if(filtro.getProvincia() != null) {
    Predicate predicateProvincia;
    predicateProvincia = builder.and(builder.equal(root.get("ot").get("provincia").get("id"), filtro.getProvincia().getId()));
    predFinal.getExpressions().add(predicateProvincia);
}
if(filtro.getPais() != null) {
    Predicate predicatePais;
    predicatePais = builder.and(builder.equal(root.get("ot").get("pais").get("id"), filtro.getPais().getId()));
    predFinal.getExpressions().add(predicatePais);
}
predFinal.getExpressions().add(builder.and(builder.isNull(root.get("fechaBaja"))));
criteria.where(predFinal);
// Query execution
Query<Tarea> query = session.createQuery(criteria);

生成的查询语句如下:

Hibernate: 
    select
        t1_0.id,
        t1_0.fk_idPedidoVenta,
        t1_0.fk_idClasificacionTarea,
        t1_0.confirmado,
        t1_0.fk_idUsuarioCreacion,
        t1_0.fechaCreacion,
        t1_0.fechaBaja,
        t1_0.fechaInicio,
        t1_0.fechaFin,
        t1_0.finalizado,
        t1_0.horaInicio,
        t1_0.horaFin,
        t1_0.observaciones,
        t1_0.fk_idTipoTarea 
    from
        Tarea t1_0 
    where
        1=1 
    order by
        t1_0.fechaInicio

问题原因与解决方案

问题根源

直接调用predFinal.getExpressions().add()添加条件的方式是错误的。CriteriaBuilder创建的conjunction()和disjunction()返回的是不可变的Predicate实例,手动修改其内部的表达式集合不会被Hibernate识别,最终只会保留初始的空conjunction(对应SQL的1=1)。

正确实现方式

应该通过CriteriaBuilder的and()/or()方法组合Predicate,推荐用List收集所有条件后统一组合:

修改后的完整代码:

// Create CriteriaBuilder
CriteriaBuilder builder = session.getCriteriaBuilder();
// Create CriteriaQuery
CriteriaQuery<Tarea> criteria = builder.createQuery(Tarea.class);
// Set root
Root<Tarea> root = criteria.from(Tarea.class);
criteria.select(root);

// 排序逻辑保留
if(getSortColumn()!= null && !getSortColumn().equals("")) {
    criteria.orderBy(builder.asc(root.get(getSortColumn())));
}

// 用List收集所有需要的Predicate条件
List<Predicate> predicates = new ArrayList<>();

// 分类过滤条件
if(filtro.getClasificacionTarea() != null && filtro.getClasificacionTarea().size()>0) {
    Predicate predClasificacion = builder.disjunction();
    for(Clasificacion clas : filtro.getClasificacionTarea()) {
        predClasificacion.getExpressions().add(builder.equal(root.get("clasificacion").get("id"), clas.getId()));
    }
    predicates.add(predClasificacion);
}

// 项目过滤条件
if(filtro.getProyecto() != null) {
    predicates.add(builder.equal(root.get("OT").get("proyecto"), filtro.getProyecto()));
}

// 客户过滤条件
if(filtro.getCliente() != null) {
    predicates.add(builder.equal(root.get("ot").get("cliente").get("id"), filtro.getCliente().getId()));
}

// 省份过滤条件
if(filtro.getProvincia() != null) {
    predicates.add(builder.equal(root.get("ot").get("provincia").get("id"), filtro.getProvincia().getId()));
}

// 国家过滤条件
if(filtro.getPais() != null) {
    predicates.add(builder.equal(root.get("ot").get("pais").get("id"), filtro.getPais().getId()));
}

// 排除已删除的数据
predicates.add(builder.isNull(root.get("fechaBaja")));

// 将所有条件组合成conjunction(逻辑与),设置到查询中
criteria.where(builder.and(predicates.toArray(new Predicate[0])));

// Query execution
Query<Tarea> query = session.createQuery(criteria);

关键修改点说明

  1. 用List<Predicate>替代直接创建conjunction(),动态收集所有过滤条件
  2. 移除每个条件中多余的builder.and()包裹(单个条件不需要额外的逻辑与操作)
  3. 最后通过builder.and(predicates.toArray(...))将所有条件组合成逻辑与的Predicate,确保所有条件生效
  4. 分类过滤的disjunction()内部添加表达式是有效的,因为此时Predicate还在构建过程中(未传入criteria.where()之前)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 12:18:10