2017-02-13 90 views
1

我已经创建了一些org.springframework.data.jpa.domain.Specifications。现在我正在创建一个查询,在该查询中我想使用我加入的表上的规范。但是为了使用规范,我需要一个Root,但是连接给了我一个Join对象。加入JPA弹簧数据规范

有没有从Join对象转换为Root的方法?或者有没有类似于规范的东西,但对于联接?

回答

3

Tarwirdur Turon的解决方案不适合我的需要,所以我设法创建一个Root<T>把一个JoinRoot将所有方法委托给一个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>,这将缓解所有的事情...

4

您不需要Root对象。 Join对象是PathExpression接口的实例。见与工作示例从规格加入:

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; 
+0

我明白了,但我的问题是,如果我想将部件 builder.equal(join.get(JoinedEntity_.value),20L) 作为规范,我该怎么办?在这种情况下,条件很简单,但在我的情况下可能会更复杂,我想重用它。 – freafrea

+0

@freafrea我更新了答案。如果您在加入的规范中没有使用根特定的条件(例如另一个连接),则可以使用'Path '而不是'Root '将条件移至另一个方法,该方法从'toPredicate(根 ..那么代码将不会被复制。 –