关于连接的JPA spring数据规范

时间:2017-02-13 16:32:44

标签: spring-data-jpa

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

有没有办法从Join对象转换为Root?或者有什么类似于规范,但对于加入?

2 个答案:

答案 0 :(得分:7)

您不需要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;

答案 1 :(得分:5)

Tarwirdur Turon的解决方案不符合我的需要,因此我设法通过创建Join实现将Root转换为Root<T>,将所有方法委派给{{} 1}}实例。 (Join和Root是From的子接口) 虽然它有效但对我来说看起来很脏。

Tarwirdur Turon的解决方案对我不起作用,因为我已经构建了Join<?,T>并且我想找到joinEntity与规范匹配的所有Specification<JoinedEntity>,而不知道什么& #39; s&#39;内部&#39;这个规范。

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>,这会让所有事情变得轻松......