子类属性的JPA Criteria API过滤 [英] JPA Criteria API filtering on subclasses' attribute
问题描述
我具有以下实体域.
父类
@Entity
public final class SupportModuleInteraction implements Serializable {
@Id
private Long id;
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "supportModuleInteraction")
@OrderColumn
private List<Event> events;
// ... getters/setters/ other attributes ommitted
}
儿童课等级化
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "event_type")
public abstract class Event implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@ManyToOne(fetch = FetchType.EAGER)
private SupportModuleInteraction supportModuleInteraction;
}
@Entity
@DiscriminatorValue("SEARCH")
public final class SearchEvent extends Event {
@Lob
private String searchTerm;
}
我正在尝试检索任何包含包含关键字的SearchEvent的SupportModuleInteractions.
I'm trying to retrieve any SupportModuleInteractions that contain a SearchEvent containing a keyword.
这是我用来尝试检索那些SupportModuleInteractions的规范:
This is the Specification I'm using to try and retrieve those SupportModuleInteractions:
public static Specification<SupportModuleInteraction> interactionWithSearchEventContaingKeyword(String keyword) {
return new Specification<SupportModuleInteraction>() {
@Override
public Predicate toPredicate(Root<SupportModuleInteraction> smi, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
Join<SupportModuleInteraction, SearchEvent> events = smi.join("events");
return criteriaBuilder.and(
criteriaBuilder.equal(events.type(), SearchEvent.class),
criteriaBuilder.like(events.get("searchTerm"), "%" + keyword + "%"));
}
};
}
该规范未能说明Event不包含名为"searchTerm"的属性,该属性有意义,因为该属性仅存在于SearchEvent子类中.
The Specification fails saying that Event contains no attribute called "searchTerm" which makes sense as that's present only on the SearchEvent subclass.
我在这里查看了此答案关于实体层次结构的JPA2标准查询不能解决我的问题,因为查询中涉及的实体位于类层次结构之外.
I've looked at this answer here JPA2 Criteria queries on entity hierarchy which doesn't solve my issue as the entity involved in the query lies outside the class hierarchy.
作为本机SQL查询,这就是我要达到的目标:
As a native SQL query, this is what I'm trying to acheive:
SELECT *
FROM event E JOIN support_module_interaction smi ON E.support_module_interaction_id = smi.id
WHERE event_type = 'SEARCH'
AND search_term LIKE 'searchString'
更新31/08/2019
我查看了 JPA标准API:子类的查询属性并修改了规范以使用criteriaBuilder.treat(...)
没有运气:
I've looked at JPA Criteria API: query property of subclass and revised the Specification to use criteriaBuilder.treat(...)
with no luck:
public static Specification<SupportModuleInteraction> interactionWithSearchEventContaingKeyword(String keyword) {
return new Specification<SupportModuleInteraction>() {
@Override
public Predicate toPredicate(Root<SupportModuleInteraction> smi, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
Join<SupportModuleInteraction, SearchEvent> events = smi.join("events");
return criteriaBuilder.and(
criteriaBuilder.equal(events.type(), SearchEvent.class),
criteriaBuilder.like(
criteriaBuilder.treat(events.get("searchTerm"), SearchEvent.class).get("searchTerm"),
"%" + keyword + "%"));
}
};
}
推荐答案
在JPA Crtieria API中很难使用Hibernate中的各种继承策略.
The various inheritance strategies in Hibernate are rather difficult to work with in the JPA Crtieria API.
Instead of using treat()
, which is rather finicky (see HHH-9862 and related issues), generate a subquery()
expression which filters for searchTerm
and add that to your parent query.
您的总体实现尚不清楚,因此我创建了一个基本示例:
Your overall implementation is unclear, so I created a basic example:
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<SupportModuleInteraction> cq = cb.createQuery(SupportModuleInteraction.class);
Root<SupportModuleInteraction> supModIntRoot = cq.from(SupportModuleInteraction.class);
Join<SupportModuleInteraction, Event> supModIntEventJoin = supModIntRoot.join("events");
// Instantiate the Subquery and Root objects for your subclass entity
Subquery<SearchEvent> searchEventSubquery = cq.from(SearchEvent.class);
Root<SearchEvent> searchEventRoot = searchEventSubquery.from(SearchEvent.class);
// Generate the subquery and filter based on the given parameter
searchEventSubquery.select(searchEventRoot);
searchEventSubquery.where(cb.like(searchEventRoot.get("searchTerm", "%" + searchTerm + "%");
// add subquery to where clause in parent query
cq.select(supModIntRoot);
cq.where(supModIntEventJoin.in(searchEventSubquery), //other subqueries and filters...);
这篇关于子类属性的JPA Criteria API过滤的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!