关于连接的JPA spring数据规范

fre*_*rea 5 spring-data-jpa

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

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

Tar*_*ron 7

你不需要Root对象.Joinobject是PathExpression接口的实例.请参阅使用规范中的join的示例:

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);
Run Code Online (Sandbox Code Playgroud)

它会提供类似的查询

SELECT e FROM Entity e LEFT JOIN e.joinedEntity j WITH j.someExpr=10 WHERE j.value = 20;
Run Code Online (Sandbox Code Playgroud)


Ghu*_*dyl 5

Tarwirdur Turon的解决方案不适合我的需要,所以我成功地把一个JoinRoot通过创建一个Root<T>实现,所有方法委托给一个Join<?,T>实例.(加入和Root是From的子接口)虽然它有效但对我来说看起来很脏.

Tarwirdur Turon的解决方案对我不起作用,因为我已经构建了一个Specification<JoinedEntity>,我想找到EntityjoinEntity与规范匹配的所有内容,而不知道这个规范的内部是什么.

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");
    }
}
Run Code Online (Sandbox Code Playgroud)

然后使用这个类如下:

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);
Run Code Online (Sandbox Code Playgroud)

我真的很想知道为什么这个Specification.toPredicate方法采用Root<X>第一个参数而不是a From<Z,X>,这会让所有事情变得轻松......