我已經創建了一些org.springframework.data.jpa.domain.Specifications。現在我正在創建一個查詢,在該查詢中我想使用我加入的表上的規範。但是爲了使用規範,我需要一個Root,但是連接給了我一個Join對象。加入JPA彈簧數據規範
有沒有從Join對象轉換爲Root的方法?或者有沒有類似於規範的東西,但對於聯接?
我已經創建了一些org.springframework.data.jpa.domain.Specifications。現在我正在創建一個查詢,在該查詢中我想使用我加入的表上的規範。但是爲了使用規範,我需要一個Root,但是連接給了我一個Join對象。加入JPA彈簧數據規範
有沒有從Join對象轉換爲Root的方法?或者有沒有類似於規範的東西,但對於聯接?
Tarwirdur Turon的解決方案不適合我的需要,所以我設法創建一個Root<T>
把一個Join
成Root
將所有方法委託給一個Join<?,T>
實例的實現。 (Join和Root是From的子接口) 儘管它起作用,但它對我來說看起來很髒。因爲我有一個已經建成Specification<JoinedEntity>
,我想找到該joinedEntity不知道什麼是「內部」本說明書中的規格相匹配的所有Entity
Tarwirdur Turon的解決方案並不爲我工作。
public class JoinRoot<T> implements Root<T> {
private final Join<?, T> join;
public JoinRoot(Join<?, T> join) {
this.join = join;
}
// implements all Root methods, delegating them to 'this.join' (#boilerplate),
// cast when needed
@Override
public EntityType<T> getModel() {
// this one is the only one that cannot be delegated, although it's not used in my use case
throw new UnsupportedOperationException("getModel cannot be delegated to a JoinRoot");
}
}
然後使用這個類像如下:
Specification<JoinedEntity> joinedSpecs = ...
Specification<Entity> specs = (root, query, builder) -> {
// Convert Join into Root using above JoinRoot class
Root<JoinedEntity> r = new JoinRoot<>(root.join(Entity_.joinedEntity));
return joinedSpecs.toPredicate(r, query, builder);
}
Specification<Entity> where = Specifications.where(specs);
List<Entity> entities = entityRepository.findAll(where);
我真的不知道爲什麼Specification.toPredicate
方法採用Root<X>
作爲第一個參數,而不是From<Z,X>
,這將緩解所有的事情...
您不需要Root
對象。 Join
對象是Path
和Expression
接口的實例。見與工作示例從規格加入:
class JoinedSpecification extends Specification<JoinedEntity>() {
public Predicate pathPredicate(Path<JoinedEntity> joinedEntity, CriteriaQuery<?> query, CriteriaBuilder builder) {
return builder.equal(joinedEnity.get(JoinedEntity_.value), 20L);
}
@Override
public Predicate toPredicate(Root<JoinedEntity> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
return pathPredicate(root, query, builder);
}
}
class MySpecification extends Specification<Entity>() {
private static JoinedSpecification joinedSpecification = new JoinedSpecification();
@Override
public Predicate toPredicate(Root<Entity> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
Join<T, JoinedEntity> join = root.join(Entity_.joinedEntity, JoinType.LEFT);
// Some join condition
Path<Long> someExpr = join.get(JoinedEntity_.someExpr);
Long someExprCriteria = 10L;
join = join.on(builder.equal(someExpr, someExprCriteria));
return joinedSpecification.pathPredicate(join, query, builder);
}
}
@Autowired
JpaSpecififcationExecutor<Entity> service;
Specification<Entity> spec = new MySpecification();
serivce.findAll(spec);
它將提供查詢像
SELECT e FROM Entity e LEFT JOIN e.joinedEntity j WITH j.someExpr=10 WHERE j.value = 20;
我明白了,但我的問題是,如果我想將部件 builder.equal(join.get(JoinedEntity_.value),20L) 作爲規範,我該怎麼辦?在這種情況下,條件很簡單,但在我的情況下可能會更復雜,我想重用它。 – freafrea
@freafrea我更新了答案。如果您在加入的規範中沒有使用根特定的條件(例如另一個連接),則可以使用'Path'而不是'Root '將條件移至另一個方法,該方法從'toPredicate(根 ..那麼代碼將不會被複制。 –