Spring-Data-JPA with QueryDslPredicateExecutor and Joining into a collection

前端 未结 2 1698
南旧
南旧 2021-02-01 07:29

Let\'s say I have a data model like this (pseudocode):

@Entity
Person {
    @OneToMany
    List attributes;
}

@Entity
PersonAttribute {
          


        
相关标签:
2条回答
  • 2021-02-01 08:07

    In order to perform more complex queries I've created my custom QueryDslRepository with support of JPQL queries and spring data JPA pagination.

    Interface:

    public interface QueryDslRepository<T> {
    
        Page<T> findAll(JPQLQuery<T> jpqlQuery, Pageable pageable);
    
    }
    

    Implementation:

    @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);
        }
    
    }
    

    Example of use:

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

    Actual repository invocation:

     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());
    
    0 讨论(0)
  • 2021-02-01 08:11

    You can't directly join a column in a predicate but you can create an any() expressions like this

    QPerson.person.attributes.any().attributeValue.eq("X")
    

    This approach has the restriction that the join expression QPerson.person.attributes.any() can be used in only one filter. It has though the benefit that this expression is internally converted into a subquery which doesn't conflict with paging.

    For multiple restrictions you will need to construct a subquery expression explicitly like this

    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()
    

    In addition to QueryDslPredicateExecutor you can also use Querydsl queries via Spring Data like this

    public class CustomerRepositoryImpl
     extends QueryDslRepositorySupport
     implements CustomerRepositoryCustom {
    
        public Iterable<Customer> findAllLongtermCustomersWithBirthday() {
            QCustomer customer = QCustomer.customer;
            return from(customer)
               .where(hasBirthday().and(isLongTermCustomer()))
               .list(customer);
        }
    }
    

    Example taken from here https://blog.42.nl/articles/spring-data-jpa-with-querydsl-repositories-made-easy/

    0 讨论(0)
提交回复
热议问题