hibernate CriteriaQuery和CriteriaBuilder未给出预期结果

tzcvj98z  于 2023-10-23  发布在  其他
关注(0)|答案(2)|浏览(136)

我正在使用CriteriaQuery和CriteriaBuilder来挂载一个动态where。我有一些过滤值,用户选择,可以通知或不。但是使用合取 predicate 并不能返回正确的where子句。这是我的代码:

// 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

Where子句总是1=1,所以它返回所有记录。
这是我第一次使用CriteriaBuilder,所以也许我用错了?谢谢你的帮助

9rnv2umw

9rnv2umw1#

您不能更新Predicate的表达式。从Predicate.getExpressions()(强调是添加的):
返回 predicate 的顶级合取词或析取词。如果 predicate 没有顶级合取词或析取词,则返回空列表。修改列表不影响查询。
conj()似乎不是一个好方法:
创建一个合取(零合取)。合取为零的合取为真。
因此,不要使用conjuction(),而是创建一个List<Predicate>,添加到它,然后使用它:

criteria.where(predicateList.toArray(Predicate[]::new));

或者,我认为这就是conjuction()存在的原因,不要添加到它的表达式中,而是替换 predicate 本身:

// predFinal.getExpressions().add(predClasificacion);
predFinal = builder.and(predFinal, predClasificacion);
wqnecbli

wqnecbli2#

这可能是因为您使用Predicate.getExpressions来收集 predicate 。根据文档,将 predicate 直接添加到这个列表不会影响查询,也就是说,该方法很可能返回 predicate 列表的防御副本。为了解决这个问题,我会手动创建一个Predicate s的列表:

final List<Predicate> predicates = new ArrayList<>();

将各个 predicate 添加到它(基于if条件),然后使用CriteriaBuilder.and获得合取:

criteria.select(root).where(predicates.toArray(Predicate[]::new));

相关问题