当前位置: 首页 > 知识库问答 >
问题:

如何按不同JPA规范的获取属性进行排序

刘绍晖
2023-03-14

我使用Spring Boot1.5.3。发布,对于我来说,不清楚如何根据嵌套对象的属性对其进行排序,这些嵌套对象具有不同的规范,因为:

原因:org。postgresql。util。PSQLException:错误:对于SELECT DISTINCT,ORDER BY表达式必须出现在SELECT列表中

Spring Data JPA生成了错误的查询。

让我们看一个小例子:

@Data
@Entity
@Table(name = "vehicle")
public class Vehicle implements Serializable {

    @Id
    @GeneratedValue(strategy = IDENTITY)
    private Long id;

    @ManyToOne
    @JoinColumn(name = "vehicle_type_id")
    private VehicleType vehicleType;

    @ManyToOne
    @JoinColumn(name = "vehicle_brand_id")
    private VehicleBrand vehicleBrand;
}

我们有Vehicle类和嵌套对象VehicleTypeVehicleBrand

@Data
@Entity
@Table(name = "vehicle_brand")
public class VehicleBrand implements Serializable {

    @Id
    @GeneratedValue(strategy = IDENTITY)
    private Long id;

    @Column(name = "name")
    private String name;

    @ManyToOne
    @JoinColumn(name = "vehicle_model_id")
    private VehicleModel model;

}

车辆品牌还包含车辆模型

@Data
@Entity
@Table(name = "vehicle_model")
public class VehicleModel implements Serializable {

    @Id
    @GeneratedValue(strategy = IDENTITY)
    private Long id;

    @Column(name = "name")
    private String name;
}

现在,我想用JPA规范创建一个查询,并按照“vehicleBrand.name”进行排序:

public List<Vehicle> findAll() {
    Specification<Vehicle> spec = Specifications.where(
            (root, criteriaQuery, criteriaBuilder) -> {
                criteriaQuery.distinct(true);
                return null;
            }
    );
    return vehicleRepository.findAll(spec, new Sort("vehicleBrand.name"));
}

Spring Data JPA生成以下查询:

select
    distinct vehicle0_.id as id1_0_,
    vehicle0_.gas_type as gas_type2_0_,
    vehicle0_.vehicle_brand_id as vehicle_4_0_,
    vehicle0_.vehicle_type_id as vehicle_5_0_,
    vehicle0_.year_of_issue as year_of_3_0_ 
from
    vehicle vehicle0_ 
left outer join
    vehicle_brand vehiclebra1_ 
        on vehicle0_.vehicle_brand_id=vehiclebra1_.id 
order by
    vehiclebra1_.name asc

而且它完全不起作用,因为:

在这种情况下,按表达式“VEHICLEBRA1_uu1.NAME”排序必须在结果列表中;SQL语句

为了解决这个问题,我们必须在我们的规范中获取车辆品牌

public List<Vehicle> findAll() {
    Specification<Vehicle> spec = Specifications.where(
            (root, criteriaQuery, criteriaBuilder) -> {
                criteriaQuery.distinct(true);
                root.fetch("vehicleBrand", JoinType.LEFT); //note that JoinType.INNER doesn't work in that case
                return null;
            }
    );
    return vehicleRepository.findAll(spec, new Sort("vehicleBrand.name"));
}

Spring Data JPA生成以下查询:

select
        distinct vehicle0_.id as id1_0_0_,
        vehiclebra1_.id as id1_1_1_,
        vehicle0_.gas_type as gas_type2_0_0_,
        vehicle0_.vehicle_brand_id as vehicle_4_0_0_,
        vehicle0_.vehicle_type_id as vehicle_5_0_0_,
        vehicle0_.year_of_issue as year_of_3_0_0_,
        vehiclebra1_.vehicle_model_id as vehicle_3_1_1_,
        vehiclebra1_.name as name2_1_1_ 
    from
        vehicle vehicle0_ 
    left outer join
        vehicle_brand vehiclebra1_ 
            on vehicle0_.vehicle_brand_id=vehiclebra1_.id 
    order by
        vehiclebra1_.name asc

现在它可以工作了,因为我们看到了vehiclebra1_1;。选择部分中的名称

但是,如果我需要排序车辆Brand.model.name
我做了一个额外的获取,但它不起作用:

public List<Vehicle> findAll() {
    Specification<Vehicle> spec = Specifications.where(
            (root, criteriaQuery, criteriaBuilder) -> {
                criteriaQuery.distinct(true);
                root.fetch("vehicleBrand", JoinType.LEFT).fetch("model", JoinType.LEFT);
                return null;
            }
    );
    return vehicleRepository.findAll(spec, new Sort("vehicleBrand.model.name"));
}

它生成以下查询:

select
        distinct vehicle0_.id as id1_0_0_,
        vehiclebra1_.id as id1_1_1_,
        vehiclemod2_.id as id1_2_2_,
        vehicle0_.gas_type as gas_type2_0_0_,
        vehicle0_.vehicle_brand_id as vehicle_4_0_0_,
        vehicle0_.vehicle_type_id as vehicle_5_0_0_,
        vehicle0_.year_of_issue as year_of_3_0_0_,
        vehiclebra1_.vehicle_model_id as vehicle_3_1_1_,
        vehiclebra1_.name as name2_1_1_,
        vehiclemod2_.name as name2_2_2_ 
    from
        vehicle vehicle0_ 
    left outer join
        vehicle_brand vehiclebra1_ 
            on vehicle0_.vehicle_brand_id=vehiclebra1_.id 
    left outer join
        vehicle_model vehiclemod2_ 
            on vehiclebra1_.vehicle_model_id=vehiclemod2_.id cross 
    join
        vehicle_model vehiclemod4_ 
    where
        vehiclebra1_.vehicle_model_id=vehiclemod4_.id 
    order by
        vehiclemod4_.name asc

它不起作用是因为:

在这种情况下,按表达式“VEHICLEMOD4_U4.NAME”排序必须在结果列表中;SQL语句

看看我们是如何选择车辆模块的。姓名但通过vehiclemod4_2;订购。名称

我试图直接在规范中进行排序,但也不起作用:

Specification<Vehicle> spec = Specifications.where(
        (root, criteriaQuery, criteriaBuilder) -> {
            criteriaQuery.distinct(true);
            root.fetch("vehicleBrand", JoinType.LEFT).fetch("model", JoinType.LEFT);
            criteriaQuery.orderBy(criteriaBuilder.asc(root.join("vehicleBrand", JoinType.LEFT).join("model", JoinType.LEFT).get("name")));
            return null;
        }
);

我应该怎么做才能让JPA生成正确的查询,这样我就可以根据嵌套的对象进行排序了?将Spring Boot的版本从1.5.3升级是否有意义。RELEASE2
谢谢。


共有1个答案

冯宏放
2023-03-14

这里有一个小秘密:您根本不需要使用Sort参数。

只需使用CriteriaQuery。订购人

Specification<Vehicle> spec = Specifications.where(
            (root, criteriaQuery, criteriaBuilder) -> {
                criteriaQuery.distinct(true);
                var model = root.fetch("vehicleBrand", JoinType.LEFT).fetch("model", JoinType.LEFT);
                criteriaQuery.orderBy(criteriaBuilder.asc(model.get("name"));
                return null;
            }
    );
    return vehicleRepository.findAll(spec));

Sort参数很可能是在您的场景中添加额外连接的原因。

 类似资料:
  • 我使用jhipster标准和jpa规范来实现进行研究的endpoint。 嗯,这是工作,但继续给我发送副本。 这个模型有一些前提条件 公司与前置站的关系 这是我用来创建规范的CompanySpecification类,我把它交给了存储库 这是我使用它的服务方法 我在CriteriaQuery中发现了一个不同的方法,但我真的不知道如何在我的规范中添加它。 请帮帮忙!

  • 问题内容: 我想按属性排序。这是我的代码… 现在我想按属性将其排序,例如在另一个活动中。但是我不知道该怎么做。有人知道吗? 问题答案: 您需要实现,例如: 然后像这样排序:

  • 问题内容: 比方说你有一个的对象。 如果它们都具有int GoalScored变量,则如何排序?你如何按GoalScored排序? 问题答案: 你可以使用Collections.sort自定义Comparator 。 比较部分也可以这样写: 或者,你可以制作。这定义了所有对象的自然顺序。使用a 更灵活,因为不同的实现可以按名称,年龄等进行排序。

  • 我正在使用一个JPA查询,它使用一个规范来检索实体。当我执行查询时,我得到了一个错误: 组织。springframework。数据映射。PropertyReferenceException:找不到类型任务的属性名称! 我已经查看了之前在该网站上提出的类似问题的答案 当我使用调试器逐步检查代码时,条件生成器中的扩展路径将返回嵌入的ID类,但当规范实际用于查询时,该属性似乎正在应用于基本实体类。 我是

  • 我正在尝试使用Spring数据JPA Specification来查询数据,但这里有一些问题。Java代码如下: 当我注释代码“收件人NoticeJoin.fetch(UserNoticeEntity_. user, JoinType. INNER);”时,它工作正常,但当我取消注释时,我会得到错误: 所以,我想知道使用规范方式是否支持连接获取,或者我的代码有问题。我知道使用@Query(“一些h

  • 问题内容: 如果我有一个JavaScript对象,例如: 有没有一种方法可以基于值对属性进行排序?这样我最终 问题答案: 将它们移动到一个数组,对该数组进行排序,然后将其用于您的目的。这是一个解决方案: 拥有数组后,您可以按自己喜欢的顺序从数组中重建对象,从而完全实现了您打算要做的事情。在我所知道的所有浏览器中都可以使用,但这取决于实现的怪癖,并且可能随时中断。您永远不应假设JavaScript对