带有 Querydsl 的 JPA 谓词

Posted

技术标签:

【中文标题】带有 Querydsl 的 JPA 谓词【英文标题】:JPA predicate with Querydsl 【发布时间】:2016-08-04 21:26:21 【问题描述】:

我在我的应用程序中使用 Querydsl 来极大地改进查询数据库的代码。 但是,我有一个来自外部服务的 JPA 谓词 (javax.persistence.criteria.Predicate)。 我想混合使用 Querydsl 和外部谓词创建的查询。例如:

// JPA Predicate from external service
Root<User> root = ...;
CriteriaBuilder cb = ...;
javax.persistence.criteria.Predicate externalPredicate = externalService.filterEmail(root, cb, "%@gmail.com");

// Create Querydsl predicate
BooleanExpression querydslExp = QUser.username.eq("foo");

// Mix predicates (this is what I need)
querydslExp.and(externalPredicate);

另一种解决方案是将 Querydsl 谓词转换为 JPA 谓词:

cb.and(querydslExp.toJpaPredicate(), externalPredicate);

有可能吗? 如果是,我该如何实现? 如果没有,是否有另一种混合谓词的解决方案(比如将两者都转换为 SQL 字符串并创建一个新查询)?

谢谢

【问题讨论】:

您想混合使用两种完全不同的 API?据我所知,不能这样做,原因很明显......它们是替代品 【参考方案1】:

使用返回 JPA 标准 Expression 并使用 CriteriaBuilderCriteriaQuery 作为上下文的 QueryDSL 表达式 Visitor 很有可能做到这一点:

CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Object> query = criteriaBuilder.createQuery();

javax.persistence.criteria.Expression<?> result = expression.accept(new Visitor<javax.persistence.criteria.Expression<?>, CriteriaBuilder>() 
    @Override
    public javax.persistence.criteria.Expression<?> visit(Constant<?> expr, CriteriaBuilder context) 
        return context.literal(expr.getConstant());
    

    @Override
    public javax.persistence.criteria.Expression<?> visit(FactoryExpression<?> expr, CriteriaBuilder context) 
        throw new UnsupportedOperationException();
    

    @Override
    public javax.persistence.criteria.Expression<?> visit(Operation<?> expr, CriteriaBuilder context) 
        javax.persistence.criteria.Expression<?>[] arguments = new javax.persistence.criteria.Expression<?>[expr.getArgs().size()];
        for (int i = 0; i < expr.getArgs().size(); i++) 
            // Visit arguments recursively
            arguments[i] = expr.getArg(i).accept(this, context);
        

        if (expr.getOperator() instanceof Ops) 
            switch ((Ops) expr.getOperator()) 
                // For example, add more...
                case EQ:
                    return context.equal(arguments[0], arguments[1]);
                default:
                    // Assuming expr.getOperator().name() as function here is not always enough,
                    // it would be better to use a switch on various operation types.
                    return context.function(expr.getOperator().name(), expr.getType(), arguments);
            
        

    

    @Override
    public javax.persistence.criteria.Expression<?> visit(ParamExpression<?> expr, CriteriaBuilder context) 
        return context.parameter(expr.getType(), expr.getName());
    

    @Override
    public javax.persistence.criteria.Expression<?> visit(Path<?> expr, CriteriaBuilder context) 
        if (expr.getMetadata().isRoot()) 
            // Get query root
            return query.getRoots().stream().filter(r -> r.getAlias().equals(expr.getMetadata().getName())).findAny().get();
        

        // Get parent path
        javax.persistence.criteria.Path<?> parent = (javax.persistence.criteria.Path<?>) expr.getMetadata().getParent().accept(this, context);
        return parent.get(expr.getMetadata().getName());
    

    @Override
    public javax.persistence.criteria.Expression<?> visit(SubQueryExpression<?> expr, CriteriaBuilder context) 
        // Defenitely possible
        throw new UnsupportedOperationException();
    

    @Override
    public javax.persistence.criteria.Expression<?> visit(TemplateExpression<?> expr, CriteriaBuilder context) 
        // No real JPA equivalent exist. ORM-specifically there are possibilities.
        throw new UnsupportedOperationException();
    
, criteriaBuilder);

【讨论】:

我对 querydsl-sql 有疑问,但找不到解决方案。如果你看,我会很高兴***.com/questions/65378623/…

以上是关于带有 Querydsl 的 JPA 谓词的主要内容,如果未能解决你的问题,请参考以下文章

SpringDataJpa

有没有办法通过 QueryDSL 中的谓词 API 急切地获取惰性关系?

带有谓词的弹簧数据 JPA 方法 findAll() - QueryDslPredicateExecutor

附加 QueryDSL 谓词或基于过滤器值构建谓词

为 oneTomany 基于关系的查询编写 queryDSL 谓词查询

QueryDSL 4 与 RowNumber Window 功能