JPA规范按本地SQL字段排序

时间:2020-03-04 17:56:16

标签: spring jpa spring-data-jpa spring-data jpql

我正在使用Spring Boot v1.5.3 在我的代码中,我有很多条件的搜索操作。

public Page<ParentObject> search(Pageable pageable) {
    Specification<ParentObject> specification = (root, cq, cb) -> {
        Predicate p = cb.and(
            cb.equals(root.get("child").get("id"), "someValue"),
            // a lot of predicates appended by conditions
            );
        return p;
    };
    Sort newSort = pageable.getSort().and(new Sort(Sort.Direction.ASC, "child.id"));
    pageable = new PageRequest(pageable.getPageNumber(), pageable.getPageSize(), newSort)
    Page<ParentObject> result = parentObjectRepository.findAll(specification, pageable);
    return result;
}

问题是我的parent表包含带有索引的child_id字段。我希望SQL像这样:

SELECT .... FROM parent p INNER JOIN child c ON c.id = p.child_id WHERE ... 
ORDER BY p.child_id ASC;

但是结果是:

SELECT .... FROM parent p INNER JOIN child c ON c.id = p.child_id WHERE ... 
ORDER BY c.id ASC;

请注意ORDER BY子句。如果我有c.id,则不涉及索引,搜索速度慢。如果我有ORDER BY p.child_id,它的运行速度会更快。 我尝试使用

Sort newSort = pageable.getSort().and(new Sort(Sort.Direction.ASC, "child"));

,但无法正常工作。 实体:

public class ParentObject {
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "child_id", referencedColumnName = "id")
    private ChildObject child;
}

我无法用本机SQL替换它,因为此搜索规范包含30多个if / else语句,并且将需要大量时间来重写代码。

如何解决此问题?预先感谢您的回答。

1 个答案:

答案 0 :(得分:0)

最后,我找到了解决方案。众所周知,ORM通过实体与数据库一起工作。 我所有的实体都有String(UUID)值作为ID。因此,我将以下代码添加到了ParentObject中:

public class ParentObject {
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "child_id", referencedColumnName = "id")
    private ChildObject child;

    @Column(name = "child_id", insertable = false, updatable = false)
    private String childId;
}

如您所见,在这里我添加了一个简单的字段,其中包含子对象的ID。将此字段标记为insertable = false, updatable = false很重要,我们不能在代码中更改此字段,这是只读字段。但这使我们能够按parent.child_id而不是child.id对结果进行排序。如果需要替换子对象,只需调用setChild(newValue)

最后,我的搜索方法现在看起来像:

public Page<ParentObject> search(Pageable pageable) {
    Specification<ParentObject> specification = (root, cq, cb) -> {
        Predicate p = cb.and(
            cb.equals(root.get("child").get("id"), "someValue"),
            // a lot of predicates appended by conditions
            );
        return p;
    };
     // IMPORTANT change in next line
    Sort newSort = pageable.getSort().and(new Sort(Sort.Direction.ASC, "childId"));
    pageable = new PageRequest(pageable.getPageNumber(), pageable.getPageSize(), newSort)
    Page<ParentObject> result = parentObjectRepository.findAll(specification, pageable);
    return result;
}

结果,我有以下SQL查询:

SELECT .... FROM parent p INNER JOIN child c ON c.id = p.child_id WHERE ... 
ORDER BY p.child_id ASC;

希望这对某人有用