我创建了这两个实体来证明我的问题:
OwnerEntity.java:
@Entity
public class OwnerEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Size(min = 1)
@OneToMany(mappedBy = "ownerEntity", cascade = CascadeType.ALL)
private Set<ChildEntity> childEntities = new HashSet<>();
}
ChildEntity.java:
@Entity
public class ChildEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@NotNull
@ManyToOne(optional = false)
private OwnerEntity ownerEntity;
public ChildEntity() {
}
public Long getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public OwnerEntity getOwnerEntity() {
return ownerEntity;
}
public void setOwnerEntity(OwnerEntity ownerEntity) {
this.ownerEntity = ownerEntity;
}
}
我想编写一个查询,显示来自OwnerEntity的信息和一个加入的ChildEntity。我创建了一个投影:
OwnerEntityProjection.java:
public interface OwnerEntityProjection {
Long getId();
String getName();
}
我的JpaRepository:
public interface OwnerEntityRepository extends JpaRepository<OwnerEntity, Long> {
@Query(" SELECT " +
" ownerEntity.id AS id, " +
" childEntities.name AS name " +
" FROM OwnerEntity ownerEntity " +
" JOIN ownerEntity.childEntities childEntities ")
// There must be also WHERE clause, but for demonstration it is omitted
Slice<OwnerEntityProjection> findAllPaginated(Pageable pageRequest);
}
现在,当我运行这个简单的测试时:
@Test
public void findAllPaginatedTest() {
Pageable pageRequest = new PageRequest(0, 3, Sort.Direction.ASC, "name");
Slice<OwnerEntityProjection> OwnerEntityProjectionsPaginated =
ownerEntityRepository.findAllPaginated(pageRequest);
}
我收到了以下错误:
org.hibernate.QueryException: could not resolve property: name of: com.example.domain.OwnerEntity
我还检查了日志中生成的JQPL:
... order by ownerEntity.name asc
正如您所见,Spring Data Jpa从FROM子句附加了第一个实体别名。我发现如果我将PageRequest更改为:
new PageRequest(0, 3, Sort.Direction.ASC, "childEntities.name");
它没有错误,但我不想将排序属性传递给存储库,其中包含JPQL查询中的别名。我想传递存储库方法返回的投影中直接存在的属性。如果我在JPQL查询中手动编写ORDER BY,如下所示:
... ORDER BY name ASC
然后这个查询也运行没有任何错误,因为我可以从ORDER BY子句中引用SELECT子句中的别名。 有没有办法告诉Spring Data Jpa执行排序而不添加FROM或JOIN子句中的别名?像这样:
new PageRequest(0, 3, Sort.Direction.ASC, "name") ===> ORDER BY name asc
答案 0 :(得分:3)
这是Spring Data中的错误:别名检测不正确。据报道here。
在applySorting
方法的QueryUtils中,仅检测到(外部)连接别名和带有一对括号的函数别名。一个简单的属性别名当前不起作用。
为此,一种解决方法是在构建JpaSort.unsafe
时使用PageRequest
和括号中的别名,例如
PageRequest.of(0, 3, JpaSort.unsafe(Sort.Direction.ASC, "(name)"))
顾名思义,这在基于用户输入进行动态排序时是不安全的,因此仅应用于硬编码排序。
答案 1 :(得分:1)
在Pageable控制器的入口点的上下文中,我将Dario Seidl的答案调整为以下内容:
public static Pageable parenthesisEncapsulation(final Pageable pageable) {
Sort sort = Sort.by(Collections.emptyList());
for (final Sort.Order order : pageable.getSort()) {
if (order.getProperty().matches("^\\(.*\\)$")) {
sort = sort.and(JpaSort.unsafe(order.getDirection(), order.getProperty()));
} else {
sort = sort.and(Sort.by(order.getDirection(), order.getProperty()));
}
}
return PageRequest
.of(pageable.getPageNumber(), pageable.getPageSize(), sort);
}
我可以这样给控制器排序指令:
/ myroute?sort =(unsafesortalias),desc&sort = safesortfield,asc
答案 2 :(得分:0)
String orderSort=page.getSort().toString();
Pageable page1 =
PageRequest.of(page.getPageNumber(),page.getPageSize(),
JpaSort.unsafe(Sort.Direction.valueOf
(orderSort.substring(page.getSort().toString().indexOf(':')+2,
orderSort.length())),
orderSort.substring(0,page.getSort().toString().indexOf(')')+1)));