JPA 规范按本机 SQL 字段排序
JPA Specification sort by native SQL field
我正在使用 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
table 包含带索引的 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个语句,重写代码会花很多时间
我该如何解决这个问题?预先感谢您的回答。
终于找到了解决办法。正如我们所知,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;
希望这对某人有用
我正在使用 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
table 包含带索引的 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个语句,重写代码会花很多时间
我该如何解决这个问题?预先感谢您的回答。
终于找到了解决办法。正如我们所知,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;
希望这对某人有用