Java 如何在SpringDataJPA中使用分页按别名从SELECT子句对投影进行排序?

Java 如何在SpringDataJPA中使用分页按别名从SELECT子句对投影进行排序?,java,spring-data-jpa,Java,Spring Data Jpa,我创建了这两个实体来演示我的问题: OwnerEntity.java: @Entity public class OwnerEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Size(min = 1) @OneToMany(mappedBy = "ownerEntity", cascade = CascadeType.ALL) p

我创建了这两个实体来演示我的问题:

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<>();
}
@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();

}
我的假设:

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);

}
我还检查了日志中生成的JQPL:

... order by ownerEntity.name asc
正如您可以看到的,SpringDataJPA附加了from子句中的第一个实体别名。我发现如果我将PageRequest更改为:

new PageRequest(0, 3, Sort.Direction.ASC, "childEntities.name");
它可以正常工作,但我不想将ordering属性传递给具有JPQL查询中某个别名的存储库。我希望传递存储库方法返回的投影中直接存在的属性。如果我在JPQL查询中手动写入订单,如下所示:

... ORDER BY name ASC
new PageRequest(0, 3, Sort.Direction.ASC, "name") ===> ORDER BY name asc
然后这个查询也会运行,没有任何错误,因为我可以从ORDERBY子句中引用SELECT子句中的别名。 有没有办法告诉SpringDataJPA执行排序,而不从from或JOIN子句中附加别名?大概是这样的:

... ORDER BY name ASC
new PageRequest(0, 3, Sort.Direction.ASC, "name") ===> ORDER BY name asc

这是Spring数据中的一个错误:未正确检测别名。也有报道

applySorting
方法中,仅检测到(外部)连接别名和具有一对括号的函数别名。属性的简单别名当前不起作用

一种解决方法是在构建
PageRequest
时使用带括号中别名的
JpaSort.unsafe
,例如

PageRequest.of(0, 3, JpaSort.unsafe(Sort.Direction.ASC, "(name)"))

顾名思义,当根据用户输入动态排序时,这是不安全的,因此只能用于硬编码排序。

在可分页控制器入口点的上下文中,我将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);
}
我可以这样给控制器排序指令:

... ORDER BY name ASC
new PageRequest(0, 3, Sort.Direction.ASC, "name") ===> ORDER BY name asc
/myroute?排序=(未安全排序),描述和排序=安全排序字段,asc


你能解决这个问题吗?对于解决方案,我也面临同样的问题。它救了我一天谢谢,它也救了我一天!非常感谢你!这是非常有用的,非常感谢!虽然这段代码可以解决这个问题,但如何以及为什么解决这个问题将真正有助于提高您的帖子质量,并可能导致更多的投票。请记住,你是在将来回答读者的问题,而不仅仅是现在提问的人。请在回答中添加解释,并说明适用的限制和假设。