我已经有了一些已创建的org.springframework.data.jpa.domain.Specifications。现在我正在创建一个查询,在这个查询中,我想使用规范来操作加入的表格。但是为了使用Specification,我需要一个Root,但是加入操作会给我一个Join对象。
是否有一种方法可以将Join对象转换为Root?或者是否有类似于Specification的东西,但是用于Join操作?
我已经有了一些已创建的org.springframework.data.jpa.domain.Specifications。现在我正在创建一个查询,在这个查询中,我想使用规范来操作加入的表格。但是为了使用Specification,我需要一个Root,但是加入操作会给我一个Join对象。
是否有一种方法可以将Join对象转换为Root?或者是否有类似于Specification的东西,但是用于Join操作?
Join
转化为一个Root
,通过创建一个Root<T>
实现,将所有方法委托给一个Join<?,T>
实例来实现。(Join和Root都是From接口的子接口)
虽然它能工作,但对我来说看起来很不干净。Specification<JoinedEntity>
,并且我想找到所有匹配该规范的Entity
,而不知道这个规范中有什么内容。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>
,如果使用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;
Path<X>
而不是 Root<X>
,然后从 toPredicate(Root<X> ...
调用。这样代码就不会重复了。 - Tarwirdur Turon