Java Spring数据JPA与QueryDSLDPredicateExecutor并加入到集合中

Java Spring数据JPA与QueryDSLDPredicateExecutor并加入到集合中,java,spring-data,spring-data-jpa,querydsl,Java,Spring Data,Spring Data Jpa,Querydsl,假设我有这样一个数据模型(伪代码): 但对于any(),它只匹配任何属性值为“blue”的对象和任何属性为“eye color”的对象,而不考虑颜色如何使这些条件应用于集合中的同一属性?您不能直接将列连接到谓词中,但可以创建一个类似以下的any()表达式 QPerson.person.attributes.any().attributeValue.eq("X") QPersonAttribute attribute = QPersonAttribute.personAttr

假设我有这样一个数据模型(伪代码):


但对于
any()
,它只匹配任何属性值为“blue”的对象和任何属性为“eye color”的对象,而不考虑颜色如何使这些条件应用于集合中的同一属性?

您不能直接将列连接到谓词中,但可以创建一个类似以下的any()表达式

QPerson.person.attributes.any().attributeValue.eq("X")
QPersonAttribute attribute = QPersonAttribute.personAttribute;
new JPASubQuery().from(attribute)
    .where(attribute.in(person.attributes),
           attribute.attributeName().name.toLowerCase().eq("eye color"),
           attribute.attributeValue.toLowerCase().eq("blue"))
     .exists()
public class CustomerRepositoryImpl
 extends QuerydslRepositorySupport
 implements CustomerRepositoryCustom {

    public Iterable<Customer> findAllLongtermCustomersWithBirthday() {
        QCustomer customer = QCustomer.customer;
        return from(customer)
           .where(hasBirthday().and(isLongTermCustomer()))
           .list(customer);
    }
}
这种方法有一个限制,即联接表达式
QPerson.person.attributes.any()
只能在一个筛选器中使用。它的好处是,这个表达式在内部被转换成一个子查询,而子查询与分页不冲突

对于多个限制,您需要像这样显式地构造子查询表达式

QPerson.person.attributes.any().attributeValue.eq("X")
QPersonAttribute attribute = QPersonAttribute.personAttribute;
new JPASubQuery().from(attribute)
    .where(attribute.in(person.attributes),
           attribute.attributeName().name.toLowerCase().eq("eye color"),
           attribute.attributeValue.toLowerCase().eq("blue"))
     .exists()
public class CustomerRepositoryImpl
 extends QuerydslRepositorySupport
 implements CustomerRepositoryCustom {

    public Iterable<Customer> findAllLongtermCustomersWithBirthday() {
        QCustomer customer = QCustomer.customer;
        return from(customer)
           .where(hasBirthday().and(isLongTermCustomer()))
           .list(customer);
    }
}
除了
Querydsl谓词执行器
之外,您还可以通过Spring数据使用Querydsl查询,如下所示

QPerson.person.attributes.any().attributeValue.eq("X")
QPersonAttribute attribute = QPersonAttribute.personAttribute;
new JPASubQuery().from(attribute)
    .where(attribute.in(person.attributes),
           attribute.attributeName().name.toLowerCase().eq("eye color"),
           attribute.attributeValue.toLowerCase().eq("blue"))
     .exists()
public class CustomerRepositoryImpl
 extends QuerydslRepositorySupport
 implements CustomerRepositoryCustom {

    public Iterable<Customer> findAllLongtermCustomersWithBirthday() {
        QCustomer customer = QCustomer.customer;
        return from(customer)
           .where(hasBirthday().and(isLongTermCustomer()))
           .list(customer);
    }
}
公共类CustomerRepositoryImpl
扩展QuerydslRepositorySupport
实现CustomerRepositoryCustom{
public Iterable findallongterm客户带生日(){
QCustomer customer=QCustomer.customer;
从(客户)处返回
.where(hasBirthday()和(isLongTermCustomer())
.名单(客户);
}
}

示例取自此处

为了执行更复杂的查询,我创建了自定义的
querydsl存储库
,支持JPQL查询和spring数据JPA分页

接口:

public interface QueryDslRepository<T> {

    Page<T> findAll(JPQLQuery<T> jpqlQuery, Pageable pageable);

}
公共接口查询存储库{
pagefindall(JPQLQuery-JPQLQuery,Pageable-Pageable);
}
实施:

@Repository
public class QueryDslRepositoryImpl<T> implements QueryDslRepository<T> {

    @PersistenceContext
    private EntityManager entityManager;

    @Override
    @SuppressWarnings("unchecked")
    public Page<T> findAll(JPQLQuery jpqlQuery, Pageable pageable) {
        Assert.notNull(jpqlQuery, "JPQLQuery must not be null!");
        Assert.notNull(pageable, "Pageable must not be null!");

        Querydsl querydsl = new Querydsl(entityManager, new PathBuilderFactory()
                                         .create(jpqlQuery.getType()));

        JPQLQuery<T> countQuery = ((AbstractJPAQuery) jpqlQuery).clone(entityManager);
        AbstractJPAQuery query = (AbstractJPAQuery) querydsl.applyPagination(pageable, jpqlQuery);
        return PageableExecutionUtils.getPage(
                  // Clone query in order to provide entity manager instance.
                  query.clone(entityManager).fetch(), 
                  pageable, 
                  countQuery::fetchCount);
    }

}
@存储库
公共类QueryDslRepositoryImpl实现QueryDslRepository{
@持久上下文
私人实体管理者实体管理者;
@凌驾
@抑制警告(“未选中”)
公共页面findAll(JPQLQuery,可分页,可分页){
Assert.notNull(jpqlQuery,“jpqlQuery不能为null!”);
Assert.notNull(pageable,“pageable不能为null!”);
Querydsl Querydsl=newquerydsl(entityManager,newPathBuilderFactory()
.create(jpqlQuery.getType());
JPQLQuery countQuery=((AbstractJPAQuery)JPQLQuery).clone(entityManager);
AbstractJPAQuery query=(AbstractJPAQuery)querydsl.applyPagination(可分页,jpqlQuery);
返回PageableExecutionUtils.getPage(
//克隆查询以提供实体管理器实例。
query.clone(entityManager.fetch(),
可分页,
countQuery::fetchCount);
}
}
使用示例:

@Repository
public interface CustomerRepository extends JpaRepository<Customer, Long>, QueryDslRepository<Customer>,
        QuerydslPredicateExecutor<Customer> {

}
@存储库
公共接口CustomerRepository扩展了JpaRepository、QueryDSL存储库、,
QueryDSL谓词执行器{
}
实际存储库调用:

 BooleanBuilder predicates = new BooleanBuilder();
 predicates = predicates.and(QCustomer.customer.active.eq(true));

 JPQLQuery<Customer> q = new JPAQuery<Customer>()
            .select(QCustomer.customer)
            // You can use .join() method here.
            .where(predicates);

 Page<Customer> result = customerRepository.findAll(q, Pageable.unpaged());
BooleanBuilder谓词=新的BooleanBuilder();
谓词=谓词和(QCustomer.customer.active.eq(true));
JPQLQuery q=newjpaquery()
.选择(QCustomer.customer)
//您可以在这里使用.join()方法。
.where(谓词);
页面结果=customerRepository.findAll(q,Pageable.unpaged());

是的,我理解。我想看看是否有一种方法可以使用QueryDslPredicateExecutor来实现这一点,这意味着我不必提供任何实现,存储库的调用者可以创建更有趣的查询,而无需通过api公开新方法。无论如何,谢谢你的回答和链接。非常好的更新,谢谢你,投了赞成票。我知道有,但不知道如何通过AttributeValue加入AttributeName并匹配它们。蒂莫,我非常感谢你在这方面花费的时间和精力。我明白,仅使用QueryDSL PredicateExecutor和spring数据jpa模块无法实现我的愿望。一点代码从来没有伤害过我,我只是想看看纯接口方法的限制是什么。新的JPASubQuery()…exists()是一个谓词,因此它与QueryDSLDPredicateExecutor兼容。我知道这很旧,但分页限制仍然适用吗?我在我的List属性上使用any()方法,除了paginingHi之外,它似乎还能工作。我希望这是我梦寐以求的快速修复方法,但根据您的示例,我或多或少地使用了它,我得到了以下错误:
org.springframework.data.mapping.PropertyReferenceException:找不到类型为Void的属性id在QueryDslRepositoryImpl.java:31(“applyPagination”行)中-我正在尝试按“id”排序