使用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);
关键修改点说明
- 用
List<Predicate>替代直接创建conjunction(),动态收集所有过滤条件 - 移除每个条件中多余的
builder.and()包裹(单个条件不需要额外的逻辑与操作) - 最后通过
builder.and(predicates.toArray(...))将所有条件组合成逻辑与的Predicate,确保所有条件生效 - 分类过滤的
disjunction()内部添加表达式是有效的,因为此时Predicate还在构建过程中(未传入criteria.where()之前)
内容的提问来源于stack exchange,提问作者Nessarose
相关产品推荐
相关产品推荐

