Rom*_*lov 7 sorting jpa distinct criteria-api spring-data-jpa
我使用 Spring Boot 1.5.3.RELEASE
,对我来说,不清楚如何按嵌套对象的属性进行排序distinct
,Specifications
原因如下:
引起:org.postgresql.util.PSQLException:错误:对于 SELECT DISTINCT,ORDER BY 表达式必须出现在选择列表中
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;
}
Run Code Online (Sandbox Code Playgroud)
我们有Vehicle
带有嵌套对象的类VehicleType
和VehicleBrand
.
@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;
}
Run Code Online (Sandbox Code Playgroud)
类VehicleBrand
还包含VehicleModel
.
@Data
@Entity
@Table(name = "vehicle_model")
public class VehicleModel implements Serializable {
@Id
@GeneratedValue(strategy = IDENTITY)
private Long id;
@Column(name = "name")
private String name;
}
Run Code Online (Sandbox Code Playgroud)
现在我想用 JPASpecifications
和一些排序来创建一个查询"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"));
}
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
它完全不起作用,因为:
在这种情况下,按表达式“VEHICLEBRA1_.NAME”排序必须在结果列表中;SQL语句
要解决这个问题,我们必须vehicleBrand
在我们的Specification
:
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"));
}
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
现在它起作用了,因为我们vehiclebra1_.name
在选择部分看到。
但是如果我需要排序"vehicleBrand.model.name"
怎么办?
我做了一个额外的fetch
,但它不起作用:
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"));
}
Run Code Online (Sandbox Code Playgroud)
它生成以下查询:
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
Run Code Online (Sandbox Code Playgroud)
它不起作用,因为:
在这种情况下,按表达式“VEHICLEMOD4_.NAME”排序必须在结果列表中;SQL语句
看看我们如何选择vehiclemod2_.name
但按 排序vehiclemod4_.name
。
我试图Specification
直接进行排序,但它也不起作用:
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;
}
);
Run Code Online (Sandbox Code Playgroud)
我应该怎么做才能让 JPA 生成正确的查询,以便我可以按嵌套对象进行排序?是否有意义,从升级春季启动的版本1.5.3.RELEASE
来2+
?
谢谢。
Sort
这里有一个小秘密:您根本不需要使用该参数。
只需使用CriteriaQuery.orderBy
:
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));
Run Code Online (Sandbox Code Playgroud)
该Sort
参数可能是在您的场景中添加额外连接的参数。
归档时间: |
|
查看次数: |
315 次 |
最近记录: |