【问题标题】:How to sort the query result by the value in one column, depending on the value in the second column using CriteriaBuilder如何根据使用 CriteriaBuilder 的第二列中的值按一列中的值对查询结果进行排序
【发布时间】:2021-09-12 13:36:48
【问题描述】:

查询是使用 Predicate 和 Specification 实现构建的,结果是返回的 Page,所示示例是整个数据库结构的简化,足以代表问题。

数据基于CarElement两个表返回。
过滤后的值基于表 Car 中的数据,该表以一对多的关系链接到表 Elements
结果应根据表Element 中的值进行排序,但仅限于manufacturer 列具有指示值的行。

如何仅在Element_.manufacturer = 5!= 5 条件下按Element_.value 排序,例如将值与null 进行比较或不对其进行排序。

@Getter
@Entity
@Immutable
@Table(name = "f_car")
public class Car {

    @Id
    private Long id;

    private String name;

    @OneToMany(fetch = FetchType.LAZY)
    @JoinColumn(name = "car_id", updatable = false, insertable = false)
    private List<Element> elements;
}
@Getter
@Entity
@Immutable
@Table(name = "f_element")
public class Element {

    @Id
    private Long id;

    @Column(name = "car_id")
    private Long carId;

    private Long manufacturer;

    private String value;
}

@AllArgsConstructor
public class SpecForView implements Specification<Car> {

    private final String name;
    private final Long manufacturerId;

    @Override
    public Predicate toPredicate(Root<Car> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {
        Predicate namePredicate = cb.equal(root.get(Car_.name), name);

       // TODO: a place in the code to set the sort
}

数据库中的样本值

【问题讨论】:

    标签: hibernate predicate specifications hibernate-criteria criteria-api


    【解决方案1】:

    通过使用 case when 语句:

    Join<Car, Element> e = root.join(Car_.elements);
    cq.orderBy(
      cb.selectCase()
        .when(
          cb.equal(e.get(Element_.manufacturer), manufacturerId), 
          e.get(Element_.value)
        ).otherwise(cb.nullLiteral(String.class))
    );
    

    【讨论】:

    • 有效!但是,此解决方案存在一个新问题,因为返回的值是重复的。例如,没有排序就返回了两个 CAR 条目,再排序后返回 4 个条目(两个 CAR 各有两个 ELEMENT 条目)。
    • 嗯,这就是您加入收藏集时所获得的。您可以使用cq.distinct() 删除重复项。
    • 我尝试调用 cq.distinct (true),但抛出异常:org.postgresql.util.PSQLException: ERROR: for SELECT DISTINCT, ORDER BY 表达式必须出现在选择列表中
    • 您需要向 Hibernate 传递一个提示以禁用通过 distinct 传递给 SQL。将hibernate.query.passDistinctThrough 设置为false
    • 您可以通过将其包装在 LinkedHashSet 中来过滤掉重复项,但如果您仍然收到重复项,我会说这是一个错误,您应该在 Hibernate 问题跟踪器中报告此问题 (@987654321 @) 并附上重现问题的测试用例 (github.com/hibernate/hibernate-test-case-templates/blob/master/…)。
    猜你喜欢
    • 2017-05-09
    • 2018-10-07
    • 1970-01-01
    • 2023-03-29
    • 1970-01-01
    • 2017-06-17
    • 1970-01-01
    • 2021-09-14
    相关资源
    最近更新 更多