[英]Spring-Data-JPA with QueryDslPredicateExecutor and Joining into a collection
假设我有一个这样的数据模型(伪代码):
@Entity
Person {
@OneToMany
List<PersonAttribute> attributes;
}
@Entity
PersonAttribute {
@ManyToOne
AttributeName attributeName;
String attributeValue;
}
@Entity
AttributeName {
String name;
}
我定义了一个 Spring-Data-JPA 存储库,例如:
public interface PersonRepository extends PagingAndSortingRepository<Person, Long>, QueryDslPredicateExecutor<Person>{}
我在 QueryDSL 文档中看到有一种机制可以从 Person 加入到 PersonAttribute,但看起来您需要访问 QueryDsl Query 对象,而存储库的客户端则没有。
我想用我的 Predicate 做的是找到所有那些具有值为“blue”的 AttributeValue(有一个连接)和一个名为“eyecolor”的 AttributeName(还有另一个连接)的人。 我不确定我将如何使用any()
来做到这一点,并强制我只得到具有 eye_color=blue 的那些而不是那些具有 shoes_color=blue 的那些。
我希望我能做这样的事情:
QPerson person = QPerson.person;
QPersonAttribute attribute = person.attributes.any();
Predicate predicate = person.name.toLowerCase().startsWith("jo")
.and(attribute.attributeName().name.toLowerCase().eq("eye color")
.and(attribute.attributeValue.toLowerCase().eq("blue")));
但是使用any()
时,它只匹配具有“蓝色”属性值的任何内容以及具有“眼睛颜色”属性的任何内容,而不管颜色如何。 如何使这些条件适用于集合中的相同属性?
您不能直接在谓词中加入列,但您可以创建这样的 any() 表达式
QPerson.person.attributes.any().attributeValue.eq("X")
这种方法的限制是连接表达式QPerson.person.attributes.any()
只能在一个过滤器中使用。 它的好处是这个表达式在内部被转换成一个不与分页冲突的子查询。
对于多个限制,您需要像这样显式地构造一个子查询表达式
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()
除了QueryDslPredicateExecutor
之外,您还可以像这样通过 Spring Data 使用 Querydsl 查询
public class CustomerRepositoryImpl
extends QuerydslRepositorySupport
implements CustomerRepositoryCustom {
public Iterable<Customer> findAllLongtermCustomersWithBirthday() {
QCustomer customer = QCustomer.customer;
return from(customer)
.where(hasBirthday().and(isLongTermCustomer()))
.list(customer);
}
}
示例取自此处https://blog.42.nl/articles/spring-data-jpa-with-querydsl-repositories-made-easy/
为了执行更复杂的查询,我创建了自定义QueryDslRepository
,支持 JPQL 查询和 spring 数据 JPA 分页。
界面:
public interface QueryDslRepository<T> {
Page<T> findAll(JPQLQuery<T> 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);
}
}
使用示例:
@Repository
public interface CustomerRepository extends JpaRepository<Customer, Long>, QueryDslRepository<Customer>,
QuerydslPredicateExecutor<Customer> {
}
实际存储库调用:
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());
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.